diff --git a/SAS/TMSS/backend/services/CMakeLists.txt b/SAS/TMSS/backend/services/CMakeLists.txt
index 8b345edf35df93e8b6b44a28369e0b7da436bf14..cae17112663c207a295defd76d05918c1b7b8156 100644
--- a/SAS/TMSS/backend/services/CMakeLists.txt
+++ b/SAS/TMSS/backend/services/CMakeLists.txt
@@ -9,5 +9,5 @@ lofar_add_package(TMSSLTAAdapter tmss_lta_adapter)
 lofar_add_package(TMSSRAAdapter tmss_ra_adapter)
 lofar_add_package(TMSSSlackWebhookService slackwebhook)
 lofar_add_package(TMSSPreCalculationsService precalculations_service)
-
+lofar_add_package(TMSSSipGenerationService sip_generation)
 
diff --git a/SAS/TMSS/backend/services/sip_generation/CMakeLists.txt b/SAS/TMSS/backend/services/sip_generation/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b6d77ab43ad0c83b806f805980a61fa14ecf928a
--- /dev/null
+++ b/SAS/TMSS/backend/services/sip_generation/CMakeLists.txt
@@ -0,0 +1,10 @@
+lofar_package(TMSSSipGenerationService 0.1 DEPENDS TMSSClient PyCommon pyparameterset PyMessaging)
+
+lofar_find_package(PythonInterp 3.4 REQUIRED)
+
+IF(NOT SKIP_TMSS_BUILD)
+    add_subdirectory(lib)
+    add_subdirectory(test)
+ENDIF(NOT SKIP_TMSS_BUILD)
+
+add_subdirectory(bin)
diff --git a/SAS/TMSS/backend/services/sip_generation/bin/CMakeLists.txt b/SAS/TMSS/backend/services/sip_generation/bin/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5e36034574d8d80101fe6796cbb3e8d245c07a0f
--- /dev/null
+++ b/SAS/TMSS/backend/services/sip_generation/bin/CMakeLists.txt
@@ -0,0 +1,4 @@
+lofar_add_bin_scripts(tmss_sip_generation_service)
+
+# supervisord config files
+lofar_add_sysconf_files(tmss_sip_generation_service.ini DESTINATION supervisord.d)
diff --git a/SAS/TMSS/backend/services/sip_generation/bin/tmss_sip_generation_service b/SAS/TMSS/backend/services/sip_generation/bin/tmss_sip_generation_service
new file mode 100755
index 0000000000000000000000000000000000000000..bf0a492cba21e3c11c930c873864b7c3c422d8e9
--- /dev/null
+++ b/SAS/TMSS/backend/services/sip_generation/bin/tmss_sip_generation_service
@@ -0,0 +1,24 @@
+#!/usr/bin/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/>.
+
+
+from lofar.sas.tmss.services.sip_generation import main
+
+if __name__ == "__main__":
+    main()
diff --git a/SAS/TMSS/backend/services/sip_generation/bin/tmss_sip_generation_service.ini b/SAS/TMSS/backend/services/sip_generation/bin/tmss_sip_generation_service.ini
new file mode 100644
index 0000000000000000000000000000000000000000..33fb5faab83fb34997905700cd7f899351f99267
--- /dev/null
+++ b/SAS/TMSS/backend/services/sip_generation/bin/tmss_sip_generation_service.ini
@@ -0,0 +1,9 @@
+[program:tmss_sip_generation_service]
+command=docker run --rm -u 7149:7149 -v /opt/lofar/var/log:/opt/lofar/var/log -v /tmp/tmp -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro -v /localhome/lofarsys:/localhome/lofarsys --env-file /localhome/lofarsys/.lofar/.lofar_env -e HOME=/localhome/lofarsys -e USER=lofarsys nexus.cep4.control.lofar:18080/tmss_django:latest /bin/bash -c 'source ~/.lofar/.lofar_env;source $LOFARROOT/lofarinit.sh;exec tmss_sip_generation_service'
+user=lofarsys
+stopsignal=INT ; KeyboardInterrupt
+stopasgroup=true ; bash does not propagate signals
+stdout_logfile=%(program_name)s.log
+redirect_stderr=true
+stderr_logfile=NONE
+stdout_logfile_maxbytes=0
diff --git a/SAS/TMSS/backend/services/sip_generation/lib/CMakeLists.txt b/SAS/TMSS/backend/services/sip_generation/lib/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f74123066248fd6fd8d0ffb7886a4b9a3ea8b205
--- /dev/null
+++ b/SAS/TMSS/backend/services/sip_generation/lib/CMakeLists.txt
@@ -0,0 +1,10 @@
+lofar_find_package(PythonInterp 3.4 REQUIRED)
+include(PythonInstall)
+
+set(_py_files
+    sip_generation.py
+    )
+
+python_install(${_py_files}
+    DESTINATION lofar/sas/tmss/services)
+
diff --git a/SAS/TMSS/backend/services/sip_generation/lib/sip_generation.py b/SAS/TMSS/backend/services/sip_generation/lib/sip_generation.py
new file mode 100644
index 0000000000000000000000000000000000000000..ddb1bb093c83864f68c1f53f516a671a339238ea
--- /dev/null
+++ b/SAS/TMSS/backend/services/sip_generation/lib/sip_generation.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python3
+
+# sip_generation.py
+#
+# Copyright (C) 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: sip_generation.py 1580 2015-09-30 14:18:57Z loose $
+
+"""
+The Sip generation service generates a Sip for each dataproduct when their TMSS subtask finished.
+It listens on the lofar notification message bus for state changes of TMSS subtasks; when a task finished,
+it loops over all dataproducts and generates a Sip (rest action) one at a time, and puts them in a lookup table.
+This is to avoid peaks of load on the system during Ingest, where many Sips are requested in bulk.
+"""
+
+import os
+from optparse import OptionParser
+import logging
+logger = logging.getLogger(__name__)
+
+from lofar.sas.tmss.client.tmssbuslistener import *
+from lofar.sas.tmss.client.tmss_http_rest_client import TMSSsession
+
+class TMSSSipGenerationEventMessageHandler(TMSSEventMessageHandler):
+    '''
+    '''
+    def __init__(self, tmss_client_credentials_id: str=None):
+        super().__init__()
+        self.tmss_client = TMSSsession.create_from_dbcreds_for_ldap(tmss_client_credentials_id)
+
+    def start_handling(self):
+        self.tmss_client.open()
+        super().start_handling()
+
+    def stop_handling(self):
+        super().stop_handling()
+        self.tmss_client.close()
+
+    def onSubTaskStatusChanged(self, id: int, status: str):
+        super().onSubTaskStatusChanged(id, status)
+
+        if status == "finished":
+            dataproducts = self.tmss_client.get_subtask_output_dataproducts(id)
+            dataproduct_ids = sorted([d['id'] for d in dataproducts])
+
+            logger.info("subtask %s finished. trying to generate SIPs for its dataproducts: %s",
+                        id, ', '.join(str(id) for id in dataproduct_ids) or 'None')
+
+            for dataproduct_id in dataproduct_ids:
+                try:
+                    self.tmss_client.get_dataproduct_SIP(dataproduct_id)
+                except Exception as e:
+                    logger.error(f'Error when generating SIP for dataproduct id={dataproduct_id}: {e}')
+
+
+def create_sip_generation_service(exchange: str=DEFAULT_BUSNAME, broker: str=DEFAULT_BROKER, tmss_client_credentials_id: str=None):
+    return TMSSBusListener(handler_type=TMSSSipGenerationEventMessageHandler,
+                                  handler_kwargs={'tmss_client_credentials_id': tmss_client_credentials_id},
+                                  exchange=exchange,
+                                  broker=broker)
+
+def main():
+    # make sure we run in UTC timezone
+    os.environ['TZ'] = 'UTC'
+
+    logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.INFO)
+
+    # Check the invocation arguments
+    parser = OptionParser('%prog [options]', description='run the tmss_sip_generation_service which automatically triggers generation of SIPs for dataproducts of finished subtasks (so that load is reduced during ingest)')
+    parser.add_option('-q', '--broker', dest='broker', type='string', default=DEFAULT_BROKER, help='Address of the messaging broker, default: %default')
+    parser.add_option('--exchange', dest='exchange', type='string', default=DEFAULT_BUSNAME, help='Name of the exchange on the messaging broker, default: %default')
+    parser.add_option('-t', '--tmss_client_credentials_id', dest='tmss_client_credentials_id', type='string',
+                      default=os.environ.get("TMSS_CLIENT_DBCREDENTIALS", "TMSSClient"),
+                      help='the credentials id for the file in ~/.lofar/dbcredentials which holds the TMSS http REST api url and credentials, default: %default')
+    (options, args) = parser.parse_args()
+
+    with create_sip_generation_service(options.exchange, options.broker, options.tmss_client_credentials_id):
+        waitForInterrupt()
+
+if __name__ == '__main__':
+    main()
diff --git a/SAS/TMSS/backend/services/sip_generation/test/CMakeLists.txt b/SAS/TMSS/backend/services/sip_generation/test/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..476e284b6dc219bce4ff96102cd03ff67089642e
--- /dev/null
+++ b/SAS/TMSS/backend/services/sip_generation/test/CMakeLists.txt
@@ -0,0 +1,7 @@
+# $Id: CMakeLists.txt 32679 2022-01-06 15:00:00Z jkuensem $
+
+if(BUILD_TESTING)
+    include(LofarCTest)
+
+    lofar_add_test(t_sip_generation_service)
+endif()
diff --git a/SAS/TMSS/backend/services/sip_generation/test/t_sip_generation_service.py b/SAS/TMSS/backend/services/sip_generation/test/t_sip_generation_service.py
new file mode 100755
index 0000000000000000000000000000000000000000..3aab47018a17268a2854513e1c23f1b28be020fe
--- /dev/null
+++ b/SAS/TMSS/backend/services/sip_generation/test/t_sip_generation_service.py
@@ -0,0 +1,157 @@
+#!/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/>.
+
+import unittest
+import uuid
+
+import logging
+logger = logging.getLogger('lofar.'+__name__)
+
+from lofar.common.test_utils import skip_integration_tests
+if skip_integration_tests():
+    exit(3)
+
+from lofar.messaging.messagebus import TemporaryExchange, BusListenerJanitor
+from lofar.sas.tmss.services.sip_generation import create_sip_generation_service
+
+import time
+
+class TestSipGenerationService(unittest.TestCase):
+    '''
+    Tests for the SipGenerationService
+    '''
+
+    # feedback doc (needs %-formatting with subband number)
+    feedback_doc = """{"percentage_written": 0, 
+                       "frequency": {"subbands": [%s], 
+                                     "beamlet_indices": [%s], 
+                                     "central_frequencies": [102734375.0], 
+                                     "channel_width": 3051.757812, 
+                                     "channels_per_subband": 64}, 
+                       "time": {"start_time": "2021-01-29T12:39:00Z", 
+                                "duration": 0.0, 
+                                "sample_width": 1.006633}, 
+                       "antennas": {"set": "HBA_DUAL", 
+                                    "fields": [{"station": "CS001", 
+                                                "field": "HBA",
+                                                "type": "HBA"}, 
+                                               {"station": "CS001", 
+                                                "field": "HBA1",
+                                                "type": "HBA"}]}, 
+                       "target": {"pointing": {"direction_type": "J2000", 
+                                               "angle1": 0.1, 
+                                               "angle2": 0.2, 
+                                               "target": "my_source"}, 
+                                  "coherent": true}, 
+                       "samples": {"polarisations": ["XX", "XY", "YX", "YY"], 
+                                   "type": "float", 
+                                   "bits": 32, 
+                                   "writer": "lofarstman", 
+                                   "writer_version": "3", 
+                                   "complex": true}, 
+                       "$schema": "http://127.0.0.1:8000/api/schemas/dataproductfeedbacktemplate/feedback/1#", 
+                       "files": []
+                       }"""
+
+    @classmethod
+    def setUpClass(cls) -> None:
+        cls.TEST_UUID = uuid.uuid1()
+
+        cls.tmp_exchange = TemporaryExchange("%s_%s" % (cls.__name__, cls.TEST_UUID))
+        cls.tmp_exchange.open()
+
+        # override DEFAULT_BUSNAME
+        import lofar
+        lofar.messaging.config.DEFAULT_BUSNAME = cls.tmp_exchange.address
+
+        # import here, and not at top of module, because DEFAULT_BUSNAME needs to be set before importing
+        from lofar.sas.tmss.test.test_environment import TMSSTestEnvironment
+
+        cls.tmss_test_env = TMSSTestEnvironment(exchange=cls.tmp_exchange.address, populate_schemas=True, start_sip_generation_service=True, start_postgres_listener=True)
+        cls.tmss_test_env.start()
+
+        from lofar.sas.tmss.test.tmss_test_data_rest import TMSSRESTTestDataCreator
+        cls.test_data_creator = TMSSRESTTestDataCreator(cls.tmss_test_env.django_server.url,
+                                                        (cls.tmss_test_env.ldap_server.dbcreds.user,
+                                                         cls.tmss_test_env.ldap_server.dbcreds.password))
+
+    @classmethod
+    def tearDownClass(cls) -> None:
+        cls.tmss_test_env.stop()
+        cls.tmp_exchange.close()
+
+    def test_sip_generation_service_generates_sip_when_subtask_finished(self):
+        # create and start the service (the object under test)
+        service = create_sip_generation_service(exchange=self.tmp_exchange.address, tmss_client_credentials_id=self.tmss_test_env.client_credentials.dbcreds_id)
+        with BusListenerJanitor(service):
+            with self.tmss_test_env.create_tmss_client() as tmss_client:
+                # create a subtask with some output dataproducts
+                dataproduct_feedback_templates = tmss_client.get_path_as_json_object('dataproduct_feedback_template')
+                empty_dataproduct_feedback_template = next(x for x in dataproduct_feedback_templates if x['name']=='empty')
+
+                dataproduct_specifications_templates = tmss_client.get_path_as_json_object('dataproduct_specifications_template')
+                visibilities_specifications_template = next(x for x in dataproduct_specifications_templates if x['name']=='visibilities')
+
+                subtask_templates = tmss_client.get_path_as_json_object('subtask_template')
+                obs_subtask_template = next(x for x in subtask_templates if x['name']=='observation control')
+
+                subtask = self.test_data_creator.post_data_and_get_response_as_json_object(self.test_data_creator.Subtask(specifications_template_url=obs_subtask_template['url']), '/subtask/')
+                subtask_id = subtask['id']
+                subtask_output = self.test_data_creator.post_data_and_get_response_as_json_object(self.test_data_creator.SubtaskOutput(subtask_url=subtask['url']), '/subtask_output/')
+                NUM_DATAPRODUCTS = 4
+                for i in range(NUM_DATAPRODUCTS):
+                    sap_template_url = tmss_client.get_path_as_json_object('sap_template/1')['url']
+                    sap_url = self.test_data_creator.post_data_and_get_response_as_json_object(self.test_data_creator.SAP(specifications_template_url=sap_template_url), '/sap/')['url']
+                    self.test_data_creator.post_data_and_get_response_as_json_object(self.test_data_creator.Dataproduct(subtask_output_url=subtask_output['url'],
+                                                                                                                        filename="L%d_SAP000_SB%03d_uv.MS" % (subtask_id, i),
+                                                                                                                        specifications_template_url=visibilities_specifications_template['url'],
+                                                                                                                        dataproduct_feedback_template_url=empty_dataproduct_feedback_template['url'],
+                                                                                                                        dataproduct_feedback_doc=self.feedback_doc % (i,i),
+                                                                                                                        sap_url=sap_url),
+                                                                                                                        '/dataproduct/')
+
+                # check that there are initially no cached SIPs for the dataproducts
+                dataproducts = tmss_client.get_subtask_output_dataproducts(subtask_id=subtask_id)
+                self.assertEqual(NUM_DATAPRODUCTS, len(dataproducts))
+                SIPs = tmss_client.get_path_as_json_object('sip')
+                num_SIPs = len(SIPs)
+                for dataproduct in dataproducts:
+                    self.assertNotIn(dataproduct['filename'], str(SIPs))
+
+                # set subtask state to finished to trigger service
+                from lofar.sas.tmss.test.test_utils import set_subtask_state_following_allowed_transitions, Subtask
+                set_subtask_state_following_allowed_transitions(Subtask.objects.get(id=subtask_id), 'finished')
+
+                # wait for service to trigger generation of SIPs
+                for i in range(10):
+                    SIPs = tmss_client.get_path_as_json_object('sip')
+                    if len(SIPs) == num_SIPs + NUM_DATAPRODUCTS:
+                        break
+                    time.sleep(5)
+
+                # check there now is a SIP for each dataproduct in the table
+                self.assertEqual(len(SIPs), num_SIPs + NUM_DATAPRODUCTS)
+                for dataproduct in dataproducts:
+                    self.assertIn(dataproduct['filename'], str(SIPs))
+
+logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.INFO)
+
+if __name__ == '__main__':
+    #run the unit tests
+    unittest.main()
diff --git a/SAS/TMSS/backend/services/sip_generation/test/t_sip_generation_service.run b/SAS/TMSS/backend/services/sip_generation/test/t_sip_generation_service.run
new file mode 100755
index 0000000000000000000000000000000000000000..06d799539c80e8f0467354bad7b00c504e45b234
--- /dev/null
+++ b/SAS/TMSS/backend/services/sip_generation/test/t_sip_generation_service.run
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+# Run the unit test
+source python-coverage.sh
+python_coverage_test "*tmss*" t_sip_generation_service.py
+
diff --git a/SAS/TMSS/backend/services/sip_generation/test/t_sip_generation_service.sh b/SAS/TMSS/backend/services/sip_generation/test/t_sip_generation_service.sh
new file mode 100755
index 0000000000000000000000000000000000000000..97f5e765549d1b5670af320428dc93ace9b4db22
--- /dev/null
+++ b/SAS/TMSS/backend/services/sip_generation/test/t_sip_generation_service.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+./runctest.sh t_sip_generation_service
\ No newline at end of file
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/adapters/sip.py b/SAS/TMSS/backend/src/tmss/tmssapp/adapters/sip.py
index f78897af448bf150b1c4e5dcb4fe92766c4191f5..71ce09b999440a16961954a9cd129f021e6ad934 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/adapters/sip.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/adapters/sip.py
@@ -1,5 +1,5 @@
 from lofar.sas.tmss.tmss.exceptions import *
-from lofar.sas.tmss.tmss.tmssapp.models.scheduling import Dataproduct, SubtaskType, Subtask, SubtaskOutput, SubtaskState, SIPidentifier, HashAlgorithm
+from lofar.sas.tmss.tmss.tmssapp.models.scheduling import Dataproduct, SubtaskType, Subtask, SubtaskOutput, SubtaskState, SIPidentifier, HashAlgorithm, SIP
 from lofar.sas.tmss.tmss.tmssapp.models.specification import Datatype, Dataformat
 from lofar.lta.sip import siplib, ltasip, validator, constants
 from lofar.common.json_utils import add_defaults_to_json_object_for_schema
@@ -768,3 +768,9 @@ def generate_sip_for_dataproduct(dataproduct):
     validator.check_consistency(sip)
     return sip
 
+
+def get_or_create_sip_xml_for_dataproduct(dataproduct):
+    '''look up the sip document for the provided dataproduct (generate it first if it does not yet exist)'''
+    if not SIP.objects.filter(dataproduct=dataproduct).exists():
+        SIP.objects.create(dataproduct=dataproduct, sip=generate_sip_for_dataproduct(dataproduct).get_prettyxml())
+    return SIP.objects.get(dataproduct=dataproduct).sip
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0022_sip.py b/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0022_sip.py
new file mode 100644
index 0000000000000000000000000000000000000000..cf0f4b02c8e9a2a7b0742091dd9126114e4bdbfe
--- /dev/null
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0022_sip.py
@@ -0,0 +1,22 @@
+# Generated by Django 3.0.9 on 2022-01-07 16:19
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('tmssapp', '0021_subtask_immutables'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='SIP',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('sip', models.CharField(help_text='The SIP in XML form as text', max_length=1048576, null=True)),
+                ('dataproduct', models.OneToOneField(help_text='The dataproduct that this SIP describes.', on_delete=django.db.models.deletion.PROTECT, related_name='sip', to='tmssapp.Dataproduct')),
+            ],
+        ),
+    ]
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/models/scheduling.py b/SAS/TMSS/backend/src/tmss/tmssapp/models/scheduling.py
index 2fa88b67bf48e503eb1a3d9d98927b7f7444d66d..c1c48af4c87aa8a95a791bc3d0a79d2335382795 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/models/scheduling.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/models/scheduling.py
@@ -140,7 +140,12 @@ class SIPidentifier(Model):
         if model._state.adding:
             model.global_parset_identifier = SIPidentifier.objects.create(source="TMSS")
 
-
+class SIP(Model):
+    '''A SIP (Submission Information Package) is an XML document that contains provenance info of a dataproduct
+    and is required to ingest data into the LTA. While these documents can be generated on-the-fly, we keep them
+    in a table so that we can (pre-)generate them independently from the ingest itself'''
+    dataproduct = OneToOneField('Dataproduct', related_name='sip', on_delete=PROTECT, help_text='The dataproduct that this SIP describes.')
+    sip = CharField(null=True, max_length=1048576, help_text='The SIP in XML form as text')
 
 #
 # Instance Objects
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/serializers/scheduling.py b/SAS/TMSS/backend/src/tmss/tmssapp/serializers/scheduling.py
index b74a6f19739746f018195f5511c29c692546cae8..88c0c9435e33df96af134a81e45c1d0297c1a8c7 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/serializers/scheduling.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/serializers/scheduling.py
@@ -199,3 +199,8 @@ class SIPidentifierSerializer(serializers.HyperlinkedModelSerializer):
         model = models.SIPidentifier
         fields = ['unique_identifier', 'source', 'url']
 
+
+class SIPSerializer(serializers.HyperlinkedModelSerializer):
+    class Meta:
+        model = models.SIP
+        fields = '__all__'
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/scheduling.py b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/scheduling.py
index 4d4f906597733f7520537b83ef9f32c21a410677..dd955448b66546b08438653f89357f366cd828f1 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/scheduling.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/scheduling.py
@@ -406,15 +406,15 @@ class DataproductViewSet(LOFARViewSet):
                          operation_description="Get the Submission Information Package (SIP) for this dataproduct")
     @action(methods=['get'], detail=True, url_name="sip")
     def sip(self, request, pk=None):
-        from lofar.sas.tmss.tmss.tmssapp.adapters.sip import generate_sip_for_dataproduct
+        from lofar.sas.tmss.tmss.tmssapp.adapters.sip import get_or_create_sip_xml_for_dataproduct
         from lofar.sas.tmss.tmss.tmssapp import views
         from django.urls import reverse
 
         # get the dataproduct...
         dataproduct = get_object_or_404(models.Dataproduct, pk=pk)
 
-        # generate the sip
-        sip = generate_sip_for_dataproduct(dataproduct).get_prettyxml()
+        # get a sip document for the dataproduct
+        sip = get_or_create_sip_xml_for_dataproduct(dataproduct)
 
         # construct the schema location for the sip
         lta_sip_xsd_path = reverse(views.get_lta_sip_xsd)
@@ -531,3 +531,8 @@ class SAPTemplateViewSet(AbstractTemplateViewSet):
 class SIPidentifierViewSet(LOFARViewSet):
     queryset = models.SIPidentifier.objects.all()
     serializer_class = serializers.SIPidentifierSerializer
+
+
+class SIPViewSet(LOFARViewSet):
+    queryset = models.SIP.objects.all()
+    serializer_class = serializers.SIPSerializer
diff --git a/SAS/TMSS/backend/src/tmss/urls.py b/SAS/TMSS/backend/src/tmss/urls.py
index bf6ccac25858b8ed51b4a7642b165662c38fb069..9d1f5cd501e52af39d3ae030edbdd9e0129595ae 100644
--- a/SAS/TMSS/backend/src/tmss/urls.py
+++ b/SAS/TMSS/backend/src/tmss/urls.py
@@ -227,6 +227,7 @@ router.register(r'subtask_state_log', viewsets.SubtaskStateLogViewSet)
 router.register(r'user', viewsets.UserViewSet)
 router.register(r'sap', viewsets.SAPViewSet)
 router.register(r'sip_identifier', viewsets.SIPidentifierViewSet)
+router.register(r'sip', viewsets.SIPViewSet)
 
 
 # PERMISSIONS
diff --git a/SAS/TMSS/backend/test/t_adapter.py b/SAS/TMSS/backend/test/t_adapter.py
index 5206c95229d9a23520d3f66c762612dd89972bff..d1dabe4c6ca8eda84b0f94993e07a5c1aba53604 100755
--- a/SAS/TMSS/backend/test/t_adapter.py
+++ b/SAS/TMSS/backend/test/t_adapter.py
@@ -66,7 +66,7 @@ from lofar.sas.tmss.tmss.workflowapp.models.schedulingunitflow import Scheduling
 from lofar.sas.tmss.tmss.exceptions import SubtaskInvalidStateException
 from lofar.sas.tmss.tmss.tmssapp.adapters.parset import convert_to_parset, convert_to_parset_dict, _order_beamformer_dataproducts
 from lofar.common.json_utils import get_default_json_object_for_schema, add_defaults_to_json_object_for_schema, resolved_remote_refs
-from lofar.sas.tmss.tmss.tmssapp.adapters.sip import generate_sip_for_dataproduct, create_sip_representation_for_dataproduct
+from lofar.sas.tmss.tmss.tmssapp.adapters.sip import generate_sip_for_dataproduct, get_or_create_sip_xml_for_dataproduct, create_sip_representation_for_dataproduct
 from lofar.lta.sip import constants
 from lofar.sas.tmss.test.test_utils import set_subtask_state_following_allowed_transitions
 from lofar.sas.tmss.tmss.tmssapp.tasks import update_task_graph_from_specifications_doc, create_scheduling_unit_blueprint_and_tasks_and_subtasks_from_scheduling_unit_draft
@@ -737,8 +737,9 @@ class SIPadapterTest(unittest.TestCase):
         # create their SIPs (separate loop since we needed to clear the cache in between):
         for i in range(10):
             dataproduct = main_dataproducts[i]
-            sip = generate_sip_for_dataproduct(dataproduct)
-            prettyxml = sip.get_prettyxml()
+            self.assertEqual(models.SIP.objects.filter(dataproduct=dataproduct).count(), 0)
+            prettyxml = get_or_create_sip_xml_for_dataproduct(dataproduct)
+            self.assertEqual(models.SIP.objects.filter(dataproduct=dataproduct).count(), 1)
             self.assertIn(str('<fileName>my_related_dataproduct_42'), prettyxml)
             self.assertIn(str(f'<fileName>my_main_dataproduct_{i}'), prettyxml)
             self.assertNotIn(str(f'<fileName>my_main_dataproduct_{i+1}'), prettyxml)
diff --git a/SAS/TMSS/backend/test/test_environment.py b/SAS/TMSS/backend/test/test_environment.py
index 4d29e96ae01509172653e3f32127fbdfa5624b16..6bdac1eaed87ddbb2e5520f11453c93820c7c84a 100644
--- a/SAS/TMSS/backend/test/test_environment.py
+++ b/SAS/TMSS/backend/test/test_environment.py
@@ -234,6 +234,7 @@ class TMSSTestEnvironment:
                  start_feedback_service: bool=False,
                  start_workflow_service: bool=False, enable_viewflow: bool=False,
                  start_precalculations_service: bool=False,
+                 start_sip_generation_service: bool=False,
                  ldap_dbcreds_id: str=None, db_dbcreds_id: str=None, client_dbcreds_id: str=None):
         self._exchange = exchange
         self._broker = broker
@@ -280,6 +281,9 @@ class TMSSTestEnvironment:
         self._start_precalculations_service = start_precalculations_service
         self.precalculations_service = None
 
+        self._start_sip_generation_service = start_sip_generation_service
+        self.sip_generation_service = None
+
         # Check for correct Django version, should be at least 3.0
         if django.VERSION[0] < 3:
             print("\nWARNING: YOU ARE USING DJANGO VERSION '%s', WHICH WILL NOT SUPPORT ALL FEATURES IN TMSS!\n" %
@@ -366,6 +370,12 @@ class TMSSTestEnvironment:
             except Exception as e:
                 logger.exception(e)
 
+        if self._start_sip_generation_service:
+            from lofar.sas.tmss.services.sip_generation import create_sip_generation_service
+            self.sip_generation_service = create_sip_generation_service(exchange=self._exchange, broker=self._broker, tmss_client_credentials_id=self.client_credentials.dbcreds_id)
+            service_threads.append(threading.Thread(target=self.sip_generation_service.start_listening()))
+            service_threads[-1].start()
+
         # wait for all services to be fully started in their background threads
         for thread in service_threads:
             thread.join()
@@ -429,6 +439,10 @@ class TMSSTestEnvironment:
             self.precalculations_service.stop()
             self.precalculations_service = None
 
+        if self.sip_generation_service is not None:
+            BusListenerJanitor.stop_listening_and_delete_queue(self.sip_generation_service)
+            self.sip_generation_service = None
+
         self.django_server.stop()
         self.ldap_server.stop()
         self.database.destroy()
@@ -559,6 +573,7 @@ def main_test_environment():
     group.add_option('-w', '--websockets', dest='websockets', action='store_true', help='Enable json updates pushed via websockets')
     group.add_option('-f', '--feedbackservice', dest='feedbackservice', action='store_true', help='Enable feedbackservice to handle feedback from observations/pipelines which comes in via the (old qpid) otdb messagebus.')
     group.add_option('-C', '--precalculations_service', dest='precalculations_service', action='store_true', help='Enable the PreCalculations service')
+    group.add_option('-G', '--sip_generation_service', dest='sip_generation_service', action='store_true', help='Enable the SIP generation service')
     group.add_option('--all', dest='all', action='store_true', help='Enable/Start all the services, upload schemas and testdata')
     group.add_option('--simulate', dest='simulate', action='store_true', help='Simulate a run of the first example scheduling_unit (implies --data and --eventmessages)')
 
@@ -597,6 +612,7 @@ def main_test_environment():
                              enable_viewflow=options.viewflow_app or options.viewflow_service or options.all,
                              start_workflow_service=options.viewflow_service or options.all,
                              start_precalculations_service=options.precalculations_service or options.all,
+                             start_sip_generation_service=options.sip_generation_service or options.all,
                              ldap_dbcreds_id=options.LDAP_ID, db_dbcreds_id=options.DB_ID, client_dbcreds_id=options.REST_CLIENT_ID) as tmss_test_env:
 
             # print some nice info for the user to use the test servers...
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/components/JSONEditor/JEditor.js b/SAS/TMSS/frontend/tmss_webapp/src/components/JSONEditor/JEditor.js
index f23dc25825f2a3c547b00154d1d9011cb2a13f45..f7ab5f16c6e3cf55e63d0a2fffa6f07997559af6 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/components/JSONEditor/JEditor.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/components/JSONEditor/JEditor.js
@@ -13,6 +13,8 @@ import $RefParser from 'json-schema-ref-parser';
 import "@fortawesome/fontawesome-free/css/all.css";
 import flatpickr from 'flatpickr';
 import "flatpickr/dist/flatpickr.css";
+import { Button } from 'primereact/button';
+
 const JSONEditor = require("@json-editor/json-editor").JSONEditor;
 
 function Jeditor(props) {
@@ -256,6 +258,8 @@ function Jeditor(props) {
                         message: 'Not a valid input. Mimimum: -90:00:00.0000degrees 0r -1.57079632679489661923, Maximum:90:00:00.0000degrees or 1.57079632679489661923'
                     });
                 }
+            } else if (schema.validationType === "transitOffset") {
+                Validator.validateTransitOffset(schema, value, errors, path);
             } else if (schema.validationType === "distanceOnSky") {
                 // To add eventlistener to the sky distance field based on the validation type set
                 if(_.indexOf(skyDistanceProps, path) === -1) {
@@ -375,7 +379,7 @@ function Jeditor(props) {
                         })
                     }
                  }
-             })
+            });
         }
         // Add Onchange event for Channels Per Subband field and Time Integration field to update Frequency Resolution and Time Resolution
         for (const channelPath of channelsPerSubbandProps) {
@@ -535,8 +539,10 @@ function Jeditor(props) {
      * Function to get the schema change for specified properties like subbands, duration, column width, etc
      * @param {Object} properties 
      */
-    function getCustomProperties(properties) {     
+    function getCustomProperties(properties, parentProps) {     
         for (const propertyKey in properties) {
+            parentProps = parentProps?parentProps:[];
+            parentProps[propertyKey] = properties[propertyKey];
             const propertyValue = properties[propertyKey];
             if ((propertyKey.toLowerCase() === 'subbands' && propertyValue.type === 'array') ||
                 propertyKey.toLowerCase() === 'list' && propertyValue.type === 'array') {                 
@@ -618,7 +624,7 @@ function Jeditor(props) {
                 propertyValue.properties['frequency_steps']['validationType'] = "pipelineAverage";
                 propertyValue.properties['frequency_steps']['format'] = "grid";
                 propertyValue.properties['frequency_steps']['options'] = { "grid_columns": 3 };
-            }   else if (propertyKey.toLowerCase() === 'duration') {               
+            }   else if (propertyKey.toLowerCase() === 'duration') {                        
                 let newProperty = {
                     "type": "string",
                     "format": "time",
@@ -645,6 +651,20 @@ function Jeditor(props) {
                         }
                     }                            
                 };                        
+                properties[propertyKey] = newProperty;
+                // durationProps.push(propertyKey);
+            }   else if (propertyKey.toLowerCase() === 'timedelta') {                        
+                let newProperty = {
+                    "type": "string",                   
+                    "title": propertyKey.toLowerCase(),
+                    "description": `${propertyValue.description?propertyValue.description:''} (+/- Hours:Minutes:Seconds)`,
+                    "options": {
+                        "grid_columns": 3,
+                        "inputAttributes": {
+                            "placeholder": "(+/-) HH:MM:SS"
+                        },                         
+                    }
+                };
 
                 properties[propertyKey] = newProperty;
                 // durationProps.push(propertyKey);
@@ -673,6 +693,21 @@ function Jeditor(props) {
                     newProperty.options.flatpickr["defaultMinute"] = systemTime.minutes();
                 }
                 properties[propertyKey] = {...propertyValue, ...newProperty};
+            }   else if (propertyValue['$ref'] && propertyValue['$ref'].toLowerCase().indexOf('#/definitions/timedelta')>=0) {
+                // set 'required' field value, it required in fields validation
+                if (parentProps && parentProps.transit_offset && parentProps.transit_offset.required) {
+                    propertyValue["required"] = _.includes(parentProps.transit_offset.required, propertyKey);
+                }
+                propertyValue["type"] = "string";
+                //propertyValue["format"] = "time";
+                propertyValue["title"] = propertyKey.toLowerCase();
+                propertyValue["description"] = `${propertyValue.description?propertyValue.description:''} (+/- Hours:Minutes:Seconds)`;
+                propertyValue["options"] = {"grid_columns": 3,
+                                            "inputAttributes": {
+                                                "placeholder": "Transit Offset [+/- Hours:Minutes:Seconds]"
+                                            }};
+                 
+                properties[propertyKey] = {...propertyValue};
             }   else if (propertyValue instanceof Object) {
                 // by default previously, all field will have format as Grid, but this will fail for calendar, so added property called skipFormat
                 if (propertyKey !== 'properties' && propertyKey !== 'default' && !propertyValue.skipFormat) {
@@ -698,7 +733,7 @@ function Jeditor(props) {
                     pointingProps.push(propertyKey);
                 }
                 
-                getCustomProperties(propertyValue);
+                getCustomProperties(propertyValue, parentProps);
             }
         }
     }
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/OffsetTimeInputmask.js b/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/OffsetTimeInputmask.js
new file mode 100644
index 0000000000000000000000000000000000000000..910dce06b3ac7d3a29912bbcd7416e82bcbc3147
--- /dev/null
+++ b/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/OffsetTimeInputmask.js
@@ -0,0 +1,44 @@
+import React, { Component } from 'react';
+import Cleave from 'cleave.js/react';
+
+const BG_COLOR= '#f878788f';
+
+export default class OffsetTimeInputMask extends Component {
+    constructor(props) {
+        super(props);
+        this.callback = this.callback.bind(this);
+    }
+
+    /**
+     * call back function to set value into grid
+     * @param {*} e 
+     */
+    callback(e) {
+        let isValid = false;
+        if (e.target.value.match('/^[\+|\-]([0-1]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/')) {
+            e.target.style.backgroundColor = '';
+            isValid = true;
+        }   else  {
+            e.target.style.backgroundColor = BG_COLOR;
+        }
+        e.target.style.border = "none";
+        this.props.context.componentParent.updateAngle(
+            this.props.node.rowIndex,this.props.colDef.field,e.target.value,false,isValid
+        );
+    }
+ 
+    afterGuiAttached(){
+        this.input.focus();
+        this.input.select();
+    }
+
+    render() {
+        return (
+            <Cleave placeholder="[+/- HH:MM:SS]" value={this.props.value}
+              title="Enter in hms format"
+              className="inputmask" 
+              htmlRef={(ref) => this.input = ref }
+              onChange={this.callback} />
+        );
+    }
+}
\ No newline at end of file
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 66cc3b59426ba8511c390522a76d2afdfacbc525..cddb94f28eaf9b37a861eddf8861a68c35617d71 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/components/Timeline/CalendarTimeline.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/components/Timeline/CalendarTimeline.js
@@ -317,8 +317,18 @@ export class CalendarTimeline extends Component {
                     <div className="sidebar-header-row">{this.state.viewType===UIConstants.timeline.types.NORMAL?
                                     (this.state.dayHeaderVisible?`Day${monthDuration}`:`Week${monthDuration}`)
                                     :`Week (${this.state.timelineStartDate.week()}) / Day`}</div> 
-                    <div className="sidebar-header-row">{this.state.dayHeaderVisible?`UTC(Hr)`:`UTC(Day)`}</div>
-                    <div className="sidebar-header-row">{this.state.dayHeaderVisible?`LST(Hr)`:`LST(Day)`}</div>
+                    <div className="sidebar-header-row">
+                        <span style={{fontSize:'10px', fontWeight: 600, backgroundColor: '#c40719', marginRight: '10px'}}>
+                            {this.cursorTime?this.cursorTime.utc.format("DD-MMM-YYYY HH:mm:00"):''}
+                        </span> 
+                        {this.state.dayHeaderVisible?`UTC(Hr)`:`UTC(Day)`}
+                    </div>
+                    <div className="sidebar-header-row">
+                        <span style={{fontSize:'10px', fontWeight: 600, backgroundColor: '#c40719', marginRight: '10px'}}>
+                            {this.cursorTime?this.cursorTime.lst:''}
+                        </span>
+                        {this.state.dayHeaderVisible?`LST(Hr)`:`LST(Day)`}
+                    </div>
                     {/* {this.state.viewType === UIConstants.timeline.types.NORMAL &&  */}
                         <div className="p-grid legend-row" 
                             style={{height:this.props.showSunTimings?'0px':'0px'}}>
@@ -693,7 +703,10 @@ export class CalendarTimeline extends Component {
     /** Custom Render function to pass to the CursorMarker component to display cursor labels on cursor movement */
     renderCursor({ styles, date }) {
         const utc = moment(date).utc();
-        this.getLSTof(utc);
+        // For week view get the row date and get the LST date of the cursor for the row date
+        let onRowGroup = _.find(this.state.group,['id', this.state.onRow]);
+        let cursorUTC = onRowGroup?onRowGroup.value.clone().hours(utc.hours()).minutes(utc.minutes()).seconds(utc.seconds()):utc;
+        this.getLSTof(cursorUTC);
         const cursorLST = this.state.cursorLST;
         let cursorTextStyles = {};
         cursorTextStyles.backgroundColor = '#c40719'
@@ -709,11 +722,13 @@ export class CalendarTimeline extends Component {
         cursorTextStyles.textAlign = "center";
         styles.backgroundColor = '#c40719';
         styles.display = "block !important";
+        styles.zIndex = '999';
+        this.cursorTime = {utc: cursorUTC, lst: cursorLST};
         return (
             <>
-                <div style={styles}  />
+                <div style={styles} />
                 <div style={cursorTextStyles}>
-                    <div>UTC: { utc.format('DD-MMM-YYYY HH:mm:00')}</div>
+                    <div>UTC: { cursorUTC.format('DD-MMM-YYYY HH:mm:00')}</div>
                     <div>LST: {cursorLST}</div>
                 </div>
             </>
@@ -754,6 +769,7 @@ export class CalendarTimeline extends Component {
                                   fontSize: isStationView?"10px":"14px",
                                   overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap",
                                   textAlign: "center"};
+        let itemStatus = null;
         if (item.type === "SCHEDULE" || item.type === "TASK" || item.type==="STATION_TASK" ) {
             itemContentStyle = {lineHeight: `${Math.floor(itemContext.dimensions.height/(isStationView?1:3))}px`, 
                                 maxHeight: itemContext.dimensions.height,
@@ -761,6 +777,7 @@ export class CalendarTimeline extends Component {
                                   overflow: "hidden", textOverflow: "ellipsis", 
                                   whiteSpace: isStationView?"nowrap":"inherit",
                                   textAlign: "center"};
+            itemStatus = item.status;
         }
         let itemDivStyle = { background: backgroundColor,
                                 color: item.color,
@@ -771,11 +788,13 @@ export class CalendarTimeline extends Component {
                             };
         if (item.type === "SCHEDULE" || item.type === "TASK" || item.type==="STATION_TASK" ) {
             itemDivStyle.border = item.scheduleMethod === 'dynamic'?"1.5px dashed":"1.5px solid"
+        }   else if (this.state.viewType === UIConstants.timeline.types.WEEKVIEW && item.type === "SUNTIME") {
+            itemStatus = "undefined";
         }
         return (
           <div 
             {...getItemProps({
-              className: `rct-item su-${item.status}`,
+              className: `rct-item ${itemStatus?'su-'+itemStatus:''}`,
               style: itemDivStyle,
               onMouseDown: () => {
                   if (item.type !== "SUNTIME") {
@@ -887,6 +906,9 @@ export class CalendarTimeline extends Component {
                 && this.props.itemMouseOverCallback) {
             this.setState({mouseEvent: true});
             this.props.itemMouseOverCallback(evt, item);
+        }   else if (this.state.viewType === UIConstants.timeline.types.WEEKVIEW && item.type === "SUNTIME") {
+            // For week view set the group id to identify the row date
+            this.setState({onRow: item.group});
         }
     }
 
@@ -900,6 +922,7 @@ export class CalendarTimeline extends Component {
             this.setState({mouseEvent: true});
             this.props.itemMouseOutCallback(evt);
         }
+        this.cursorTime = null;
     }
 
     /**
@@ -1622,81 +1645,83 @@ export class CalendarTimeline extends Component {
                     </div>
                     {/* } */}
                 </div>
+                <div onMouseOut={e => this.cursorTime = null }>
                 <Timeline
-                    groups={this.state.group}
-                    items={this.state.items}
-                    // Use these below properties to stop zoom and move
-                    // defaultTimeStart={this.props.defaultStartTime?this.props.defaultStartTime:this.state.defaultStartTime}
-                    // defaultTimeStart={this.state.defaultStartTime}
-                    // defaultTimeEnd={this.state.defaultEndTime}
-                    visibleTimeStart={this.state.defaultStartTime.valueOf()}
-                    visibleTimeEnd={this.state.defaultEndTime.valueOf()}
-                    resizeDetector={containerResizeDetector}
-                    stackItems={this.props.stackItems || false}
-                    traditionalZoom={this.state.zoomAllowed}
-                    minZoom={this.state.minZoom}
-                    maxZoom={this.state.maxZoom}
-                    lineHeight={this.props.rowHeight || 50} itemHeightRatio={1}
-                    sidebarWidth={this.props.sidebarWidth?this.props.sidebarWidth:this.state.sidebarWidth}
-                    timeSteps={this.state.timeSteps}
-                    onZoom={this.onZoom}
-                    onBoundsChange={this.onBoundsChange}
-                    onTimeChange={this.onTimeChange}
-                    itemRenderer={this.renderItem}
-                    canMove={this.state.canMove}
-                    canResize={this.state.canResize}
-                    canChangeGroup={this.state.canChangeGroup}>
-                    <TimelineHeaders className="sticky">
-                        <SidebarHeader>{({ getRootProps }) => {return this.renderSidebarHeader({ getRootProps })}}</SidebarHeader>
-                        {this.state.weekHeaderVisible &&
-                            <DateHeader unit="Week" labelFormat="w"></DateHeader> }
-                        { this.state.dayHeaderVisible  &&
-                            <DateHeader unit="hour" intervalRenderer={this.renderDayHeader}></DateHeader> }
-                        <DateHeader unit={this.state.lstDateHeaderUnit} intervalRenderer={this.renderUTCDateHeader} ></DateHeader>
-                        {!this.state.isLSTDateHeaderLoading &&
-                            // This method keeps updating the header labels, so that the LST values will be displayed after fetching from server
-                            <DateHeader unit={this.state.lstDateHeaderUnit} 
-                                        intervalRenderer={({ getIntervalProps, intervalContext, data })=>{return this.renderLSTDateHeader({ getIntervalProps, intervalContext, data })}}>
-                            </DateHeader>
-                            // This method will render once but will not update the values after fetching from server
-                            // <DateHeader unit={this.state.lstDateHeaderUnit} intervalRenderer={this.renderLSTDateHeader}></DateHeader>
-                        }
-                        {/* Suntime Header in normal view with sunrise, sunset and night time  */}
-                        {/* {this.props.showSunTimings && this.state.viewType === UIConstants.timeline.types.NORMAL && this.state.sunTimeMap && 
-                        <CustomHeader height={30} unit="minute" 
-                            children={({ headerContext: { intervals }, getRootProps, getIntervalProps, showPeriod, data})=> {
-                                return this.renderNormalSuntimeHeader({ headerContext: { intervals }, getRootProps, getIntervalProps, showPeriod, data})}}>
-                        </CustomHeader>
-                        } */}
-                    </TimelineHeaders>
+                        groups={this.state.group}
+                        items={this.state.items}
+                        // Use these below properties to stop zoom and move
+                        // defaultTimeStart={this.props.defaultStartTime?this.props.defaultStartTime:this.state.defaultStartTime}
+                        // defaultTimeStart={this.state.defaultStartTime}
+                        // defaultTimeEnd={this.state.defaultEndTime}
+                        visibleTimeStart={this.state.defaultStartTime.valueOf()}
+                        visibleTimeEnd={this.state.defaultEndTime.valueOf()}
+                        resizeDetector={containerResizeDetector}
+                        stackItems={this.props.stackItems || false}
+                        traditionalZoom={this.state.zoomAllowed}
+                        minZoom={this.state.minZoom}
+                        maxZoom={this.state.maxZoom}
+                        lineHeight={this.props.rowHeight || 50} itemHeightRatio={1}
+                        sidebarWidth={this.props.sidebarWidth?this.props.sidebarWidth:this.state.sidebarWidth}
+                        timeSteps={this.state.timeSteps}
+                        onZoom={this.onZoom}
+                        onBoundsChange={this.onBoundsChange}
+                        onTimeChange={this.onTimeChange}
+                        itemRenderer={this.renderItem}
+                        canMove={this.state.canMove}
+                        canResize={this.state.canResize}
+                        canChangeGroup={this.state.canChangeGroup}>
+                        <TimelineHeaders className="sticky">
+                            <SidebarHeader>{({ getRootProps }) => {return this.renderSidebarHeader({ getRootProps })}}</SidebarHeader>
+                            {this.state.weekHeaderVisible &&
+                                <DateHeader unit="Week" labelFormat="w"></DateHeader> }
+                            { this.state.dayHeaderVisible  &&
+                                <DateHeader unit="hour" intervalRenderer={this.renderDayHeader}></DateHeader> }
+                            <DateHeader unit={this.state.lstDateHeaderUnit} intervalRenderer={this.renderUTCDateHeader} ></DateHeader>
+                            {!this.state.isLSTDateHeaderLoading &&
+                                // This method keeps updating the header labels, so that the LST values will be displayed after fetching from server
+                                <DateHeader unit={this.state.lstDateHeaderUnit} 
+                                            intervalRenderer={({ getIntervalProps, intervalContext, data })=>{return this.renderLSTDateHeader({ getIntervalProps, intervalContext, data })}}>
+                                </DateHeader>
+                                // This method will render once but will not update the values after fetching from server
+                                // <DateHeader unit={this.state.lstDateHeaderUnit} intervalRenderer={this.renderLSTDateHeader}></DateHeader>
+                            }
+                            {/* Suntime Header in normal view with sunrise, sunset and night time  */}
+                            {/* {this.props.showSunTimings && this.state.viewType === UIConstants.timeline.types.NORMAL && this.state.sunTimeMap && 
+                            <CustomHeader height={30} unit="minute" 
+                                children={({ headerContext: { intervals }, getRootProps, getIntervalProps, showPeriod, data})=> {
+                                    return this.renderNormalSuntimeHeader({ headerContext: { intervals }, getRootProps, getIntervalProps, showPeriod, data})}}>
+                            </CustomHeader>
+                            } */}
+                        </TimelineHeaders>
 
-                    <TimelineMarkers>
-                        {/* Current time line marker */}
-                        <CustomMarker date={this.state.currentUTC}>
-                            {({ styles, date }) => {
-                                const customStyles = {
-                                ...styles,
-                                backgroundColor: 'green',
-                                width: '2px'
-                                }
-                                return <div style={customStyles} />
-                            }}
-                        </CustomMarker>
-                        {/* Show sunrise and sunset markers for normal timeline view (Not station view and week view */}
-                        {this.props.showSunTimings && this.state.viewType===UIConstants.timeline.types.NORMAL &&
-                            <>
-                            {/* Sunrise time line markers */}
-                            { this.renderSunriseMarkers(this.state.sunRiseTimings)}
-                            {/* Sunset time line markers */}
-                            { this.renderSunsetMarkers(this.state.sunSetTimings)}
-                            </>
-                        }
-                        {this.state.showCursor?
-                            <CursorMarker>
-                                {this.renderCursor}
-                            </CursorMarker>:""}
-                    </TimelineMarkers>
-                </Timeline>
+                        <TimelineMarkers>
+                            {/* Current time line marker */}
+                            <CustomMarker date={this.state.currentUTC}>
+                                {({ styles, date }) => {
+                                    const customStyles = {
+                                    ...styles,
+                                    backgroundColor: 'green',
+                                    width: '2px'
+                                    }
+                                    return <div style={customStyles} />
+                                }}
+                            </CustomMarker>
+                            {/* Show sunrise and sunset markers for normal timeline view (Not station view and week view */}
+                            {this.props.showSunTimings && this.state.viewType===UIConstants.timeline.types.NORMAL &&
+                                <>
+                                {/* Sunrise time line markers */}
+                                { this.renderSunriseMarkers(this.state.sunRiseTimings)}
+                                {/* Sunset time line markers */}
+                                { this.renderSunsetMarkers(this.state.sunSetTimings)}
+                                </>
+                            }
+                            {this.state.showCursor?
+                                <CursorMarker>
+                                    {this.renderCursor}
+                                </CursorMarker>:""}
+                        </TimelineMarkers>
+                    </Timeline>
+                </div>
             </React.Fragment>
         );
     }
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_timeline.scss b/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_timeline.scss
index 7d9bd66e394fb008ce026e73cc79d39ec215737e..45dd20d4534087b509e746141bf98d8cabc8e545 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_timeline.scss
+++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_timeline.scss
@@ -179,6 +179,12 @@
     color: orange;
 }
 
+.su-undefined {
+    height: 90% !important;
+    border-top:1px solid rgb(224, 222, 222) !important;
+    border-radius: 0px;
+}
+
 .su-visible {
     margin-top: 30px;
     // margin-left: -59px !important;
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/Scheduling.Constraints.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/Scheduling.Constraints.js
index fdb33be78e197fbb0e1108e3ae96c4dfe0011fbc..5347d7ee6b0669f9c883e90015eee27ed673b056 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/Scheduling.Constraints.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/Scheduling.Constraints.js
@@ -59,9 +59,11 @@ export default (props) => {
             }
             if(propertyKey === 'from' ){
                 propertyValue.propertyOrder=10;
+                propertyValue.validationType= 'transitOffset';
             }
             if(propertyKey === 'to'){
                 propertyValue.propertyOrder=11;
+                propertyValue.validationType= 'transitOffset';
             }
             if(propertyKey === 'sun' || propertyKey === 'moon' || propertyKey === 'jupiter'){               
                 propertyValue.default = ((propertyValue.default * 180) / Math.PI).toFixed(2);
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 5031a12c5dd31f203f377405c9cd1827eaed878e..c2b8dd2267ed422f99696ed80b638e91562ee9e0 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/SchedulingUnitList.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/SchedulingUnitList.js
@@ -98,7 +98,11 @@ class SchedulingUnitList extends Component{
         do_cancel: {
             name: "Cancelled",
             filter: "switch",
-        },    
+        },
+        targetName: {name: 'Target - Name'},
+        targetAngle1: {name: 'Target - Angle 1'},
+        targetAngle2: {name: 'Target - Angle 2'},
+        targetRef: {name: 'Target - Reference Frame'},
     }
        
         if (props.hideProjectColumn) {
@@ -137,12 +141,10 @@ class SchedulingUnitList extends Component{
                 "Stations (CS/RS/IS)", 
                 "Tasks content (O/P/I)", 
                 "Number of SAPs in the target observation", 
-                "Target 1 - Angle 1", 
-                "Target 1 - Angle 2", 
-                "Target 1 - Reference Frame", 
-                "Target 2 - Angle 1", 
-                "Target 2 - Angle 2", 
-                "Target 2 - Reference Frame",
+                "Target - Name", 
+                "Target - Angle 1", 
+                "Target - Angle 2", 
+                "Target - Reference Frame", 
                 "Created_At", 
                 "Updated_At"                
             ],
@@ -269,6 +271,7 @@ class SchedulingUnitList extends Component{
         this.copySpecAndFailedTasks = this.copySpecAndFailedTasks.bind(this);
         this.scheduleConstraintsArray=this.scheduleConstraintsArray.bind(this);
         this.capitalize = this.capitalize.bind(this);
+        this.formatListToNewLineText = this.formatListToNewLineText.bind(this);
     }
 
     capitalize(s) {
@@ -554,7 +557,7 @@ class SchedulingUnitList extends Component{
         const columnDefinitionToBeRemove = ['status', 'workflowStatus', 'on_sky_start_time', 'on_sky_stop_time', 'process_start_time', 'process_stop_time'];
         //For Constraint
         const constColDefToBeRemove = ['observation_strategy_template_name', 'duration', 'observation_strategy_template_id', 'observation_strategy_template_description', 'on_sky_start_time', 'on_sky_stop_time', 'process_start_time', 'process_stop_time', 'task_content',
-        'target_observation_sap', 'do_cancel', 'created_at', 'updated_at', 'priority_rank', 'priority_queue', 'output_pinned', 'draft',];
+        'target_observation_sap', 'do_cancel', 'created_at', 'updated_at', 'priority_rank', 'priority_queue', 'output_pinned', 'draft', 'targetName','targetAngle1','targetAngle2','targetRef'];
         const suFilters = await ScheduleService.getSchedulingUnitFilterDefinition(type);
         this.columnMap = [];
         let tmpDefaulColumns = _.cloneDeep(this.state.defaultcolumns[0]);
@@ -688,44 +691,6 @@ class SchedulingUnitList extends Component{
                         output.push(scheduleunit);
                     }
                 }  
-                output.map(su => {
-                    su.taskDetails = su.type==="Draft"?su.task_drafts:su.task_blueprints;
-                    const targetObserv = su && su.taskDetails ? su.taskDetails.find(task => task.specifications_template.type_value==='observation' && task.specifications_doc.SAPs) : null;
-                    // Constructing targets in single string to make it clear display 
-                    if (targetObserv && targetObserv.specifications_doc) {
-                        targetObserv.specifications_doc.SAPs.map((target, index) => {
-                            if (index === 0){
-                                defaultcolumns[`target${index}angle1`] = {name: `Target ${index + 1} - Angle 1`};
-                                defaultcolumns[`target${index}angle2`] = {name: `Target ${index + 1} - Angle 2`};
-                                defaultcolumns[`target${index}referenceframe`] = {
-                                    name: `Target ${index + 1} - Reference Frame`,
-                                    filter: "select"
-                                };
-                                
-                            }   else {
-                                optionalColumns[`target${index}angle1`] = {name: `Target ${index + 1} - Angle 1`};
-                                optionalColumns[`target${index}angle2`] = {name: `Target ${index + 1} - Angle 2`};
-                                optionalColumns[`target${index}referenceframe`] = {
-                                    name: `Target ${index + 1} - Reference Frame`,
-                                    filter: "select"
-                                };
-                            }
-                            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`] = {name: `Target ${index + 1} - Angle 1`};
-                            optionalColumns[`target${index}angle2`] = {name: `Target ${index + 1} - Angle 2`};
-                            optionalColumns[`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;
-                });
             }  else if ( suType.toLowerCase() === 'blueprint') {
                 const suIds = _.map(scheduleunits, 'id');
                 let workflows = await this.timelineCommonUtils.getWorkflowsAndTasks(suIds);
@@ -789,10 +754,6 @@ class SchedulingUnitList extends Component{
                     this.constraintColumns = [];                 
                     for (const key in derviedscheduleconstraints) {
                         if (key !== '$schema') {
-                            /*const header = _.includes(this.minDistance, key)?` ${this.capitalize(key).replace('_',' ')} (Degrees)`: ` ${this.capitalize(key).replace('_',' ')} `;
-                            defaultcolumns[`${key}`] = {
-                                name: header
-                            };*/
                             this.constraintColumns.push(key);
                             scheduleunit[key] = derviedscheduleconstraints[key];
                         }
@@ -812,62 +773,57 @@ class SchedulingUnitList extends Component{
         this.selectedRows = [];
     }
 
+    /**
+     * Prepare new line string in table column
+     * @param {Array} arrayVal 
+     * @returns 
+     */
+    formatListToNewLineText(arrayVal){
+        return (
+            <>
+                {arrayVal.length>0 && arrayVal.map((item) => (
+                    <div>{item}</div>
+                ))}
+            </>
+        );                    
+    }
+
+    /**
+     * Group the target values into 4 columns
+     * @param {*} schedulingUnits 
+     */
     async addTargetColumns(schedulingUnits) {
-        let optionalColumns = this.state.optionalcolumns[0];
-        let defaultcolumns = this.state.defaultcolumns[0];
-        let columnclassname = this.state.columnclassname[0];
         let dataLoadstatus = false;
-      
-        await schedulingUnits.map(su => {
+        for (let su of schedulingUnits) {
             su['priority_queue'] = su.priority_queue_value;
             su.taskDetails = su.type==="Draft"?su.task_drafts:su.task_blueprints;
             const targetObserv =  su.taskDetails ? su.taskDetails.find(task => task.specifications_template.type_value==='observation' && (task.specifications_doc.SAPs || task.specifications_doc.target)) : null;
-            // 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) {
             su['priority_queue'] = su.priority_queue_value;
             if (targetObserv) {
                 this.suTypeColumnToBeRemove = [];
+                let targetNames = [];
+                let targetAngle1s = [];
+                let targetAngle2s = [];
+                let targetRefs = [];   
                 su['target_observation_sap'] = targetObserv.specifications_doc.target? targetObserv.specifications_doc.target.SAPs.length: targetObserv.specifications_doc.SAPs.length;
                 let SAPs = targetObserv.specifications_doc.target? targetObserv.specifications_doc.target.SAPs: targetObserv.specifications_doc.SAPs
-                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;
-                    if (index === 0 ){
-                        defaultcolumns[`target${index}angle1`] = {name: `Target ${index + 1} - Angle 1`};
-                        defaultcolumns[`target${index}angle2`] = {name: `Target ${index + 1} - Angle 2`};
-                        defaultcolumns[`target${index}referenceframe`] = {name: `Target ${index + 1} - Reference Frame`};                       
-                    }   else {
-                        optionalColumns[`target${index}angle1`] = {name: `Target ${index + 1} - Angle 1`};
-                        optionalColumns[`target${index}angle2`] = {name: `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`] = {name: `Target ${index + 1} - Reference Frame`};
-                    }
-                    this.suTypeColumnToBeRemove.push(`target${index}angle1`);
-                    this.suTypeColumnToBeRemove.push(`target${index}angle2`);
-                    this.suTypeColumnToBeRemove.push(`target${index}referenceframe`);
-                    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;
-                });
+                for (const target of SAPs) {
+                    // targetNames.push(target.digital_pointing.target) ;
+                    targetNames.push(target.name) ;
+                    targetAngle1s.push(UnitConverter.getAngleInput(target.digital_pointing.angle1));
+                    targetAngle2s.push(UnitConverter.getAngleInput(target.digital_pointing.angle2, true));
+                    targetRefs.push(target.digital_pointing.direction_type);
+                };
+                su['targetName'] = this.formatListToNewLineText(targetNames);
+                su['targetAngle1'] = this.formatListToNewLineText(targetAngle1s);
+                su['targetAngle2'] = this.formatListToNewLineText(targetAngle2s);
+                su['targetRef'] = this.formatListToNewLineText(targetRefs);
             }   else {
                 su['target_observation_sap'] = 0;
             }
-            return su;
-        });
+        }
         await this.setState({
-            scheduleunit: schedulingUnits, isLoading: false, optionalColumns: [optionalColumns],
-            columnclassname: [columnclassname], loadingStatus: dataLoadstatus
+            scheduleunit: schedulingUnits, isLoading: false, loadingStatus: dataLoadstatus
         });
         this.getFilterColumns(this.changesutype());
     }
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 f6e9f0440525cad3c34ce81bbe6d658c9825b4ec..185d69bfec18aee658ee009272fb0a8a54eb887c 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js
@@ -41,7 +41,28 @@ class ViewSchedulingUnit extends Component {
     SU_ACTIVE_STATUSES = ['started', 'observing', 'observed', 'processing', 'processed', 'ingesting'];
     SU_END_STATUSES = ['finished', 'error', 'cancelled'];
     TASK_END_STATUSES = ['finished', 'error', 'cancelled'];
-
+    SU_BLUEPRINT_EXPAND= 'draft.scheduling_constraints_template,draft,draft.scheduling_set,task_blueprints.specifications_template,task_blueprints,task_blueprints.subtasks,draft.observation_strategy_template'
+    SU_BLUEPRINT_FIELDS= ['id','url','created_at','status','tags','output_pinned','duration','name','on_sky_start_time','on_sky_stop_time','scheduling_constraints_doc','description',
+                            'updated_at','draft.url','draft.id','draft.name','draft.scheduling_set.url','draft.scheduling_set.name','draft.scheduling_set.project_id','task_blueprints.status',
+                            'draft.priority_rank','draft.priority_queue_value','task_blueprints.subtasks.id','task_blueprints.subtasks.primary','task_blueprints.subtasks.specifications_template_id',
+                            'task_blueprints.task_type','task_blueprints.id','task_blueprints.subtasks_ids','task_blueprints.name','task_blueprints.description',
+                            'task_blueprints.short_description','task_blueprints.on_sky_start_time','task_blueprints.on_sky_stop_time','task_blueprints.process_start_time',
+                            'task_blueprints.process_stop_time','task_blueprints.duration','task_blueprints.relative_start_time','task_blueprints.relative_stop_time','task_blueprints.tags', 'task_blueprints.url',
+                            'task_blueprints.do_cancel','task_blueprints.obsolete_since','task_blueprints.created_at','task_blueprints.updated_at','task_blueprints.specifications_template.id', 'task_blueprints.draft_id',
+                            'task_blueprints.specifications_template.type_value','draft.scheduling_constraints_template.schema','draft.scheduling_constraints_template.url','task_blueprints.produced_by_ids','task_blueprints.specifications_doc',
+                            'draft.observation_strategy_template_id','draft.observation_strategy_template.id', ,'draft.observation_strategy_template.template']
+    SU_DRAFT_EXPAND= 'scheduling_constraints_template,scheduling_set,task_drafts.specifications_template,task_drafts,observation_strategy_template,scheduling_unit_blueprints'
+    SU_DRAFT_FIELDS=['id','url','created_at','status','tags','output_pinned','duration','name','on_sky_start_time','on_sky_stop_time','priority_rank','priority_queue_value','description',
+                        'scheduling_constraints_doc','scheduling_constraints_template.schema','scheduling_constraints_template.url','observation_strategy_template_id','task_drafts.url','scheduling_constraints_template_id',
+                        'updated_at','scheduling_set.url','scheduling_set.name','scheduling_set.project_id','task_drafts.status','task_drafts.task_type','task_drafts.id','task_drafts.subtasks_ids',
+                        'task_drafts.name','task_drafts.description','task_drafts.short_description','task_drafts.on_sky_start_time','task_drafts.on_sky_stop_time','task_drafts.process_start_time',
+                        'task_drafts.process_stop_time','task_drafts.duration','task_drafts.relative_start_time','task_drafts.relative_stop_time','task_drafts.tags','task_drafts.do_cancel',
+                        'task_drafts.obsolete_since','task_drafts.created_at','task_drafts.updated_at','task_drafts.specifications_template.id','task_drafts.specifications_template.type_value',
+                        'task_drafts.task_blueprints_ids','task_drafts.specifications_doc','task_drafts.produced_by_ids','scheduling_unit_blueprints_ids', 
+                        'observation_strategy_template.id','observation_strategy_template.template',
+                        'scheduling_unit_blueprints.id','scheduling_unit_blueprints.name']
+                    
+                        
     constructor(props) {
         super(props);
         this.setToggleBySorting();
@@ -339,21 +360,22 @@ class ViewSchedulingUnit extends Component {
     };
 
     getSchedulingUnitDetails(schedule_type, schedule_id) {
-        ScheduleService.getSchedulingUnitExtended(schedule_type, schedule_id)
+        let expand = schedule_type.toLowerCase() === 'draft' ? this.SU_DRAFT_EXPAND: this.SU_BLUEPRINT_EXPAND;
+        let fields = schedule_type.toLowerCase() === 'draft' ? this.SU_DRAFT_FIELDS: this.SU_BLUEPRINT_FIELDS;
+        ScheduleService.getExpandedSchedulingUnit(schedule_type, schedule_id,expand,fields)
             .then(async (schedulingUnit) => {
                 if (schedulingUnit) {
-                    ScheduleService.getSchedulingConstraintTemplate(schedulingUnit.scheduling_constraints_template_id)
-                        .then((template) => {
-                            this.setState({ scheduleunitId: schedule_id,
-                                scheduleunit: schedulingUnit,
-                                scheduleunitType: schedule_type,
-                                constraintTemplate: template })
-                        });
-                    if (schedulingUnit.draft_id) {
-                        await ScheduleService.getSchedulingUnitDraftById(schedulingUnit.draft_id).then((response) => {
-                            schedulingUnit['observation_strategy_template_id'] = response.observation_strategy_template_id;
-                        });
+                    schedulingUnit = this.formatConstraintDocForUI(schedulingUnit);
+                    if (schedulingUnit.draft) {
+                        schedulingUnit['observation_strategy_template_id'] = schedulingUnit.draft.observation_strategy_template_id;
+                        schedulingUnit['scheduling_set'] = schedulingUnit.draft.scheduling_set;
+                        schedulingUnit['scheduling_constraints_template'] = schedulingUnit.draft.scheduling_constraints_template
                     }
+                    this.setState({ scheduleunitId: schedule_id,
+                                    scheduleunit: schedulingUnit,
+                                    scheduleunitType: schedule_type,
+                                    constraintTemplate: schedulingUnit.scheduling_constraints_template})
+                    
                     let tasks = schedulingUnit.task_drafts ? (await this.getFormattedTaskDrafts(schedulingUnit)) :await this.getFormattedTaskBlueprints(schedulingUnit);
                     let ingestGroup;
                     if(this.props.match.params.type === 'draft') {
@@ -399,7 +421,8 @@ class ViewSchedulingUnit extends Component {
                                                                 && task.tasktype.toLowerCase() === schedule_type 
                                                                 && (task.specifications_doc.station_groups || task.specifications_doc.target?.station_groups) });
                     const isIngestPresent = _.find(tasks, (task) => { return task.template.type_value === 'ingest'});   
-                    await this.getFilterColumns(this.props.match.params.type.toLowerCase());         
+                    await this.getFilterColumns(this.props.match.params.type.toLowerCase());
+                                        
                     this.setState({
                         scheduleunitId: schedule_id,
                         scheduleunit: schedulingUnit,
@@ -411,7 +434,7 @@ class ViewSchedulingUnit extends Component {
                         dialogVisible: false,
                         ingestGroup
                     });
-                    this.loadTaskParameters(schedulingUnit.observation_strategy_template_id);
+                    this.loadTaskParameters(schedulingUnit.draft?schedulingUnit.draft.observation_strategy_template: schedulingUnit.observation_strategy_template);
                     this.selectedRows = [];
                     // Add Action menu
                     this.getActionMenu(schedule_type, isIngestPresent);
@@ -423,70 +446,80 @@ class ViewSchedulingUnit extends Component {
                 }
             });
     }
-
+    
+    /**
+     * Format constraint field value for UI
+     * @param {*} scheduling_constraints_doc 
+     * @returns 
+     */
+    formatConstraintDocForUI(scheduleunit) {
+        if (scheduleunit.scheduling_constraints_doc && !scheduleunit.scheduling_constraints_doc.sky.transit_offset.fromoffset) {
+            scheduleunit.scheduling_constraints_doc.sky.transit_offset.from = (scheduleunit.scheduling_constraints_doc.sky.transit_offset.from<0?'-':'')+UnitConverter.getSecsToHHmmss(scheduleunit.scheduling_constraints_doc.sky.transit_offset.from);            
+            scheduleunit.scheduling_constraints_doc.sky.transit_offset.to = (scheduleunit.scheduling_constraints_doc.sky.transit_offset.to<0?'-':'')+UnitConverter.getSecsToHHmmss(scheduleunit.scheduling_constraints_doc.sky.transit_offset.to);
+        }
+        return scheduleunit;
+    }
+    
     /**
      * To get task parameters from observation strategy to create custom json schema and load with existing value of the task as input 
      * parameters to pass to the JSON editor.
      */
-    loadTaskParameters(observationStrategyId) {
-        ScheduleService.getObservationStrategy(observationStrategyId)
-        .then(async(observStrategy) => {
-            if (observStrategy) {
-                const tasks = observStrategy.template.tasks;
-                const parameters = observStrategy.template.parameters;
-                let paramsOutput = {};
-                let schema = { type: 'object', additionalProperties: false, 
-                                properties: {}, definitions:{}
-                                };
-                let bandPassFilter = null;
-                const $strategyRefs = await $RefParser.resolve(observStrategy.template);
-                // TODo: This schema reference resolving code has to be moved to common file and needs to rework
-                for (const param of parameters) {
-                    // TODO: make parameter handling more generic, instead of task specific.
-                    if (!param.refs[0].startsWith("#/tasks/")) { continue; }
-                    let taskPaths = param.refs[0].split("/");
-                    const taskName = taskPaths[2];
-                    //taskPaths = taskPaths.slice(4, taskPaths.length);
-                    /**
-                     * For Short_Description, the task path length will be 4, so added below condition to get short_description details
-                     *  #/tasks/Combined Observation/short_description
-                     */
-                    taskPaths = taskPaths.slice((taskPaths.length===4?3:4), taskPaths.length);
-                    const task = tasks[taskName];
-                    const suTask = this.state.schedulingUnitTasks.find(taskD => taskD.name === taskName);
-                    if (suTask) { task.specifications_doc = suTask.specifications_doc;
-                        task.short_description = suTask.short_description;
-                        //task.specifications_doc = suTask.specifications_doc;
-                        const taskKeys = Object.keys(task);
-                        for (const taskKey of taskKeys) {
-                            if (taskKey !== 'specifications_template') {
-                                task[taskKey] = suTask[taskKey];
-                            }
+    async loadTaskParameters(observStrategy) {
+        if (observStrategy) {
+            const tasks = observStrategy.template.tasks;
+            const parameters = observStrategy.template.parameters;
+            let paramsOutput = {};
+            let schema = { type: 'object', additionalProperties: false, 
+                            properties: {}, definitions:{}
+                            };
+            let bandPassFilter = null;
+            const $strategyRefs = await $RefParser.resolve(observStrategy.template);
+            // TODo: This schema reference resolving code has to be moved to common file and needs to rework
+            for (const param of parameters) {
+                // TODO: make parameter handling more generic, instead of task specific.
+                if (!param.refs[0].startsWith("#/tasks/")) { continue; }
+                let taskPaths = param.refs[0].split("/");
+                const taskName = taskPaths[2];
+                //taskPaths = taskPaths.slice(4, taskPaths.length);
+                /**
+                 * For Short_Description, the task path length will be 4, so added below condition to get short_description details
+                 *  #/tasks/Combined Observation/short_description
+                 */
+                taskPaths = taskPaths.slice((taskPaths.length===4?3:4), taskPaths.length);
+                const task = tasks[taskName];
+                const suTask = this.state.schedulingUnitTasks.find(taskD => taskD.name === taskName);
+                if (suTask) { task.specifications_doc = suTask.specifications_doc;
+                    task.short_description = suTask.short_description;
+                    //task.specifications_doc = suTask.specifications_doc;
+                    const taskKeys = Object.keys(task);
+                    for (const taskKey of taskKeys) {
+                        if (taskKey !== 'specifications_template') {
+                            task[taskKey] = suTask[taskKey];
                         }
                     }
-                    if (task) {
-                        const taskTemplate = suTask.template;
-                        // Get the default Bandpass filter and pass to the editor for frequency calculation from subband list
-                        if (taskTemplate.type_value === 'observation' && task.specifications_doc.filter) {
-                            bandPassFilter = task.specifications_doc.filter;
-                        }   else if (taskTemplate.type_value === 'observation' && taskTemplate.schema.properties.filter) {
-                            bandPassFilter = taskTemplate.schema.properties.filter.default;
-                        }
-                        let taskTemplateSchema = await UtilService.resolveSchema(_.cloneDeep(taskTemplate.schema));
-                        schema.definitions = {...schema.definitions, ...taskTemplateSchema.definitions};
-                        taskPaths.reverse();
-                        const paramProp = await ParserUtility.getParamProperty($strategyRefs, taskPaths, taskTemplateSchema, this.taskFilters);
-                        schema.properties[param.name] = _.cloneDeep(paramProp);
-                        if (schema.properties[param.name]) {
-                            schema.properties[param.name].title = param.name;
-                            schema.properties[param.name].default = $strategyRefs.get(param.refs[0]);
-                            paramsOutput[param.name] = schema.properties[param.name].default; 
-                        }
+                }
+                if (task) {
+                    const taskTemplate = suTask.template;
+                    // Get the default Bandpass filter and pass to the editor for frequency calculation from subband list
+                    if (taskTemplate.type_value === 'observation' && task.specifications_doc.filter) {
+                        bandPassFilter = task.specifications_doc.filter;
+                    }   else if (taskTemplate.type_value === 'observation' && taskTemplate.schema.properties.filter) {
+                        bandPassFilter = taskTemplate.schema.properties.filter.default;
+                    }
+                    let taskTemplateSchema = await UtilService.resolveSchema(_.cloneDeep(taskTemplate.schema));
+                    schema.definitions = {...schema.definitions, ...taskTemplateSchema.definitions};
+                    taskPaths.reverse();
+                    const paramProp = await ParserUtility.getParamProperty($strategyRefs, taskPaths, taskTemplateSchema, this.taskFilters);
+                    schema.properties[param.name] = _.cloneDeep(paramProp);
+                    if (schema.properties[param.name]) {
+                        schema.properties[param.name].title = param.name;
+                        schema.properties[param.name].default = $strategyRefs.get(param.refs[0]);
+                        paramsOutput[param.name] = schema.properties[param.name].default; 
                     }
                 }
-                this.setState({paramsSchema: schema, paramsOutput: paramsOutput, bandPassFilter: bandPassFilter });
             }
-        });
+            this.setState({paramsSchema: schema, paramsOutput: paramsOutput, bandPassFilter: bandPassFilter });
+        }
     }
 
     async getFilterColumns(type) {
@@ -501,6 +534,7 @@ class ViewSchedulingUnit extends Component {
         tmpOptionalColumns = _.omit(tmpOptionalColumns,columnDefinitionToRemove)
         await this.setState({tmpDefaulcolumns: [tmpDefaulColumns], tmpOptionalcolumns:[tmpOptionalColumns], tmpColumnOrders: tmpColumnOrders, columnMap: this.columnMap})
     }
+
     /**
      * Get action menus for page header
      */
@@ -524,7 +558,7 @@ class ViewSchedulingUnit extends Component {
         });
         this.actions.push({ icon: 'fa-window-close', title: 'Click to Close Scheduling Unit View', type: 'button',  actOn: 'click', props:{ callback: this.cancelView }});
         if (this.props.match.params.type ==='draft') {           
-           let blueprintExist = this.state.scheduleunit && this.state.scheduleunit.scheduling_unit_blueprints && this.state.scheduleunit.scheduling_unit_blueprints.length>0;
+           let blueprintExist = this.state.scheduleunit && this.state.scheduleunit.scheduling_unit_blueprints_ids && this.state.scheduleunit.scheduling_unit_blueprints_ids.length>0;
             if(isIngestPresent) {
                 this.actions.unshift({
                     icon: 'fa-file-import', 
@@ -734,7 +768,7 @@ class ViewSchedulingUnit extends Component {
             dialog.onSubmit = this.createBlueprintTree;
             dialog.content = null;
             dialog.width = null;
-            if (this.state.scheduleunit.scheduling_unit_blueprints.length > 0) {
+            if (this.state.scheduleunit.scheduling_unit_blueprints_ids.length > 0) {
                 dialog.detail = "Blueprint(s) already exist for this Scheduling Unit. Do you want to create another one?";
             } else {
                 dialog.detail = "Do you want to create a Scheduling Unit Blueprint?";
@@ -1597,19 +1631,21 @@ class ViewSchedulingUnit extends Component {
       * Enable/Disable autodeletion in the scheduling unit
       */
     async setAutoDeletion() {
+        let suCopy = _.cloneDeep(this.state.scheduleunit);
         let resSU = this.state.scheduleunit;
         resSU['output_pinned'] = !this.state.scheduleunit.output_pinned;
+        resSU['draft'] = this.state.scheduleunit.draft.url;
+        resSU['scheduling_constraints_template'] = this.state.scheduleunit.scheduling_constraints_template.url;
         delete resSU['task_blueprints'];
         delete resSU['task_drafts'];
-        resSU = await ScheduleService.updateSchedulingUnit(this.props.match.params.type, resSU);
-        if (resSU) {
+        let updatedResSU = await ScheduleService.updateSchedulingUnit(this.props.match.params.type, resSU);
+        if (updatedResSU) {
             appGrowl.show({ severity: 'success', summary: 'Success', detail: 'Prevent Automatic Deletion updated successfully' });
-            let tmpSu = this.state.scheduleunit;
-            tmpSu['output_pinned'] = resSU.output_pinned;
+            suCopy['output_pinned'] = updatedResSU.output_pinned;
             var index = _.indexOf(this.actions, _.find(this.actions, {'icon' :'fa-thumbtack'}));
             this.actions.splice(index, 1, { icon: 'fa-thumbtack', title: this.state.scheduleunit.output_pinned? 'Allow Automatic Deletion' : 'Prevent Automatic Deletion', 
             type: 'button', actOn: 'click', props: { callback: this.confirmAutoDeletion } }); 
-            this.setState({scheduleunit: tmpSu, actions: this.actions, dialogVisible: false});
+            this.setState({scheduleunit: suCopy, actions: this.actions, dialogVisible: false});
         }   else {
             appGrowl.show({ severity: 'error', summary: 'Failed', detail: 'Unable to update Automatic Deletion' });
             this.setState({dialogVisible: false});
@@ -1818,35 +1854,35 @@ class ViewSchedulingUnit extends Component {
                                 <span className="col-lg-4 col-md-4 col-sm-12">{this.state.scheduleunit.observation_strategy_template_id}</span>
                             </div>
                             <div className="p-grid">
-                                {this.state.scheduleunit.scheduling_set_object.project_id &&
+                                {this.state.scheduleunit.scheduling_set && this.state.scheduleunit.scheduling_set.project_id &&
                                     <>
                                         <label className="col-lg-2 col-md-2 col-sm-12">Project</label>
                                         <span className="col-lg-4 col-md-4 col-sm-12">
-                                            <Link to={`/project/view/${this.state.scheduleunit.scheduling_set_object.project_id}`}>{this.state.scheduleunit.scheduling_set_object.project_id}</Link>
+                                            <Link to={`/project/view/${this.state.scheduleunit.scheduling_set.project_id}`}>{this.state.scheduleunit.scheduling_set.project_id}</Link>
                                         </span>
                                     </>
                                 }
                                 <label className="col-lg-2 col-md-2 col-sm-12">Scheduling set</label>
-                                <span className="col-lg-4 col-md-4 col-sm-12">{this.state.scheduleunit.scheduling_set_object.name}</span>
+                                <span className="col-lg-4 col-md-4 col-sm-12">{this.state.scheduleunit.scheduling_set && this.state.scheduleunit.scheduling_set.name}</span>
                             </div>
                             <div className="p-grid">
                                 <label className="col-lg-2 col-md-2 col-sm-12" >Priority Rank</label>
-                                <span className="col-lg-4 col-md-4 col-sm-12">{this.state.scheduleunit.priority_rank}</span>
+                                <span className="col-lg-4 col-md-4 col-sm-12">{this.state.scheduleunit.draft?this.state.scheduleunit.draft.priority_rank: this.state.scheduleunit.priority_rank}</span>
                                 <label className="col-lg-2 col-md-2 col-sm-12">Priority Queue</label>
-                                <span className="col-lg-4 col-md-4 col-sm-12">{this.state.scheduleunit.priority_queue_value}</span>
+                                <span className="col-lg-4 col-md-4 col-sm-12">{this.state.scheduleunit.draft? this.state.scheduleunit.draft.priority_queue_value : this.state.scheduleunit.priority_queue_value}</span>
                             </div>
                             <div className="p-grid">
                                 <label className="col-lg-2 col-md-2 col-sm-12">{this.props.match.params.type === 'blueprint' ? 'Draft' : 'Blueprints'}</label>
                                 <span className="col-lg-4 col-md-4 col-sm-12">
                                     <ul className="task-list">
-                                        {(this.state.scheduleunit.blueprintList || []).map(blueprint => (
+                                        {(this.state.scheduleunit.scheduling_unit_blueprints || []).map(blueprint => (
                                             <li>
                                                 <Link to={{ pathname: `/schedulingunit/view/blueprint/${blueprint.id}` }}>{blueprint.name}</Link>
                                             </li>))}
-                                        {this.state.scheduleunit.draft_object &&
+                                        {this.state.scheduleunit.draft &&
                                             <li>
-                                                <Link to={{ pathname: `/schedulingunit/view/draft/${this.state.scheduleunit.draft_object.id}` }}>
-                                                    {this.state.scheduleunit.draft_object.name}
+                                                <Link to={{ pathname: `/schedulingunit/view/draft/${this.state.scheduleunit.draft.id}` }}>
+                                                    {this.state.scheduleunit.draft.name}
                                                 </Link>
                                             </li>}
                                     </ul>
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 a048736ad2884324f4a27adea18e0b282d212aea..b0afedca78429ddc834977a1b6b352ecdea13183 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.js
@@ -162,7 +162,7 @@ export class SchedulingUnitCreate extends Component {
      * It generates the JSON schema for JSON editor and defult vales for the parameters to be captured
      * @param {number} strategyId 
      */
-     async changeStrategy (strategyId) {
+    async changeStrategy (strategyId) {
         const observStrategy = _.find(this.observStrategies, {'id': strategyId});
         let station_group = [];
         const tasks = observStrategy.template.tasks;
@@ -255,8 +255,7 @@ export class SchedulingUnitCreate extends Component {
         if (jsonOutput.scheduler === 'online' || jsonOutput.scheduler === 'dynamic') {
             err = err.filter(e => e.path !== 'root.time.at');
         }
-       // this.constraintParamsOutput = jsonOutput;
-        // condition goes here..
+        this.constraintParamsOutput = jsonOutput;
         this.constraintValidEditor = err.length === 0;
         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});
@@ -388,7 +387,7 @@ export class SchedulingUnitCreate extends Component {
             }
             if (!constStrategy.time.before) {
                 delete constStrategy.time.before;
-             }
+            }
             if (constStrategy.time[type] && constStrategy.time[type].length) {
                 if (typeof constStrategy.time[type] === 'string') {
                     constStrategy.time[type] = `${moment(constStrategy.time[type]).format("YYYY-MM-DDTHH:mm:ss.SSSSS", { trim: false })}Z`;
@@ -401,6 +400,11 @@ export class SchedulingUnitCreate extends Component {
                 }
             }
         }
+        if (constStrategy.sky.transit_offset) {
+            constStrategy.sky.transit_offset.from = UnitConversion.getHHmmssToSecs(constStrategy.sky.transit_offset.from);
+            constStrategy.sky.transit_offset.to = UnitConversion.getHHmmssToSecs(constStrategy.sky.transit_offset.to);
+        }
+
        //station
         const station_groups = [];
         (this.state.selectedStations || []).forEach(key => {
@@ -484,9 +488,11 @@ export class SchedulingUnitCreate extends Component {
         this.setState({showDialog: false});
     }
 
-    constraintStrategy(e){
+    async constraintStrategy(e){
         let schedulingUnit = { ...this.state.schedulingUnit };
         schedulingUnit.scheduling_constraints_template_id = e.id;
+        this.constraintTemplates[0].schema.properties.sky.properties.transit_offset.properties.from.default = UnitConversion.getSecsToHHmmssWithSign(this.constraintTemplates[0].schema.properties.sky.properties.transit_offset.properties.from.default);
+        this.constraintTemplates[0].schema.properties.sky.properties.transit_offset.properties.to.default = UnitConversion.getSecsToHHmmssWithSign(this.constraintTemplates[0].schema.properties.sky.properties.transit_offset.properties.to.default);
         this.setState({ constraintSchema: this.constraintTemplates[0], schedulingUnit});
      }
    
@@ -588,17 +594,15 @@ export class SchedulingUnitCreate extends Component {
     setSUSet(suSet) {
         this.setState({newSet: suSet});
     }
-
+ 
     render() {
         if (this.state.redirect) {
             return <Redirect to={ {pathname: this.state.redirect} }></Redirect>
         }
         const schema = this.state.paramsSchema;
         const {scheduleunit_draft} = this.state.userrole;
-        
         let jeditor = null;
         if (schema) {
-            
 		   jeditor = React.createElement(Jeditor, {title: "Task Parameters", 
                                                         schema: schema,
                                                         initValue: this.state.paramsOutput, 
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 9b46ee48d6b47905525e0a1846d84f8d01d71b64..50e40dc823a5df4faf6e6ac4bb39dc1234837ef5 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/edit.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/edit.js
@@ -219,10 +219,23 @@ export class EditSchedulingUnit extends Component {
             }   else {
                 this.setState({isLoading: false});
             }
-            this.constraintStrategy(this.constraintTemplates[0], this.state.schedulingUnit.scheduling_constraints_doc)
+            this.constraintStrategy(this.constraintTemplates[0],  this.formatConstraintDocForUI(this.state.schedulingUnit.scheduling_constraints_doc))
         }); 
     }
 
+    /**
+     * Format constraint field value for UI
+     * @param {*} scheduling_constraints_doc 
+     * @returns 
+     */
+    formatConstraintDocForUI(scheduling_constraints_doc) {
+        if (scheduling_constraints_doc) {
+            scheduling_constraints_doc.sky.transit_offset.from = (scheduling_constraints_doc.sky.transit_offset.from<0?'-':'')+UnitConversion.getSecsToHHmmss(scheduling_constraints_doc.sky.transit_offset.from);
+            scheduling_constraints_doc.sky.transit_offset.to = (scheduling_constraints_doc.sky.transit_offset.to<0?'-':'')+UnitConversion.getSecsToHHmmss(scheduling_constraints_doc.sky.transit_offset.to);
+        }
+        return scheduling_constraints_doc;
+    }
+
     /**
      * This is the callback method to be passed to the JSON editor. 
      * JEditor will call this function when there is change in the editor.
@@ -394,6 +407,7 @@ export class EditSchedulingUnit extends Component {
                 }
             }
         }
+
         /* for (let type in constStrategy.sky.transit_offset) {
             constStrategy.sky.transit_offset[type] = constStrategy.sky.transit_offset[type] * 60;
         }*/
@@ -412,6 +426,10 @@ export class EditSchedulingUnit extends Component {
             });
         }
         const schUnit = { ...this.state.schedulingUnit };
+        if (constStrategy.sky.transit_offset) {
+            constStrategy.sky.transit_offset.from = UnitConversion.getHHmmssToSecs(constStrategy.sky.transit_offset.from);
+            constStrategy.sky.transit_offset.to = UnitConversion.getHHmmssToSecs(constStrategy.sky.transit_offset.to);
+        }
         schUnit.scheduling_constraints_doc = constStrategy;
         //station 
         const station_groups = [];
@@ -471,8 +489,8 @@ export class EditSchedulingUnit extends Component {
         this.setState({showDialog: false});
     }
 
-    constraintStrategy(schema, initValue){
-       this.setState({ constraintSchema: schema, initValue: initValue});
+    async constraintStrategy(schema, initValue){
+        this.setState({ constraintSchema: schema, initValue: initValue});
     }
   
     onUpdateStations = (state, selectedStations, missingStationFieldsErrors, customSelectedStations) => {
@@ -685,7 +703,7 @@ export class EditSchedulingUnit extends Component {
                         <div className="p-grid p-justify-start">
                             <div className="p-col-1">
                                 <Button label="Save" className="p-button-primary" icon="pi pi-check" onClick={this.saveSchedulingUnit} 
-                                        disabled={!this.state.validEditor || !this.state.validForm} data-testid="save-btn" />
+                                        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.checkIsDirty}  />
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/excelview.schedulingset.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/excelview.schedulingset.js
index 8161da156d7adcc0967b1be8d8439208ba89dc2a..89080987537460045b65532e57c77a40762f1656 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/excelview.schedulingset.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/excelview.schedulingset.js
@@ -9,6 +9,7 @@ import { DataTable } from 'primereact/datatable';
 import { Column } from 'primereact/column';
 
 import TimeInputmask from '../../components/Spreadsheet/TimeInputmask'
+import OffsetTimeInputmask from '../../components/Spreadsheet/OffsetTimeInputmask'
 import DegreeInputmask from '../../components/Spreadsheet/DegreeInputmask'
 import NumericEditor from '../../components/Spreadsheet/numericEditor';
 import BetweenEditor from '../../components/Spreadsheet/BetweenEditor'; 
@@ -102,6 +103,7 @@ export class SchedulingSetCreate extends Component {
             frameworkComponents: {
                 numericEditor: NumericEditor,
                 timeInputMask: TimeInputmask,
+                offsetTimeInputmask:OffsetTimeInputmask,
                 degreeInputMask: DegreeInputmask,
                 betweenRenderer: BetweenRenderer,
                 betweenEditor: BetweenEditor,
@@ -808,8 +810,8 @@ export class SchedulingSetCreate extends Component {
                     observationProps['min_target_elevation'] = constraint.sky.min_target_elevation;
                     observationProps['min_calibrator_elevation'] = constraint.sky.min_calibrator_elevation;
                     if  ( constraint.sky.transit_offset ){
-                        observationProps['offset_from'] = constraint.sky.transit_offset.from?constraint.sky.transit_offset.from:0;
-                        observationProps['offset_to'] = constraint.sky.transit_offset.to?constraint.sky.transit_offset.to:0;
+                        observationProps['offset_from'] = constraint.sky.transit_offset.from?(constraint.sky.transit_offset.from<0?'-':'')+UnitConverter.getSecsToHHmmss(constraint.sky.transit_offset.from):0;
+                        observationProps['offset_to'] = constraint.sky.transit_offset.to?(constraint.sky.transit_offset.to<0?'-':'')+UnitConverter.getSecsToHHmmss(constraint.sky.transit_offset.to):0;
                         observationProps['offset_from_max'] = this.constraintSchema.schema.properties.sky.properties.transit_offset.properties.from.maximum;
                         observationProps['offset_from_min'] =  this.constraintSchema.schema.properties.sky.properties.transit_offset.properties.from.minimum;
                         observationProps['offset_to_max'] = this.constraintSchema.schema.properties.sky.properties.transit_offset.properties.to.maximum;
@@ -1124,7 +1126,8 @@ export class SchedulingSetCreate extends Component {
                         {headerName: 'Description', field: 'sudesc', cellStyle: function(params) {
                                 if  (params.data && params.data.suname && (params.data.suname !== '' && (!params.value || params.value === ''))) {
                                     return { backgroundColor: BG_COLOR};
-                                }  else  { return { backgroundColor: ''};}
+                                }  else  { 
+                                    return { backgroundColor: ''};}
                             },},
                         {headerName: 'Priority Rank', field: 'priority_rank',cellEditor: 'numericEditor', cellStyle: function(params) {
                             let value = params.data.priority_rank? params.data.priority_rank: params.data.gdef_priority_rank ? params.data.gdef_priority_rank : '';
@@ -1132,8 +1135,10 @@ export class SchedulingSetCreate extends Component {
                                 const splitValue = _.split((value+''),".");
                                 if (value < 0 || value > 1 || (splitValue.length > 1 && splitValue[1].length > 4)) {
                                     return {backgroundColor: BG_COLOR};
-                                }   else  { return {backgroundColor: ''};}
-                            }   else  { return {backgroundColor: ''};}
+                                }   else  { 
+                                    return {backgroundColor: ''};}
+                            }   else  { 
+                                return {backgroundColor: ''};}
                         }},
                         {headerName: 'Priority Queue', field: 'priority_queue',cellEditor: 'agSelectCellEditor',
                         cellEditorParams: {values: this.state.priorityQueuelist}},]
@@ -1342,8 +1347,8 @@ export class SchedulingSetCreate extends Component {
         this.agSUWithDefaultValue['scheduler'] = this.constraintSchema.schema.properties.scheduler.default;
         this.agSUWithDefaultValue['min_target_elevation'] =  ((this.constraintSchema.schema.properties.sky.properties.min_target_elevation.default * 180) / Math.PI).toFixed(2);
         this.agSUWithDefaultValue['min_calibrator_elevation'] = ((this.constraintSchema.schema.properties.sky.properties.min_calibrator_elevation.default * 180) / Math.PI).toFixed(2);
-        this.agSUWithDefaultValue['offset_from'] = 0;
-        this.agSUWithDefaultValue['offset_to'] = 0;
+        this.agSUWithDefaultValue['offset_from'] = '00:00:00';
+        this.agSUWithDefaultValue['offset_to'] = '00:00:00';
         this.agSUWithDefaultValue['offset_from_max'] = this.constraintSchema.schema.properties.sky.properties.transit_offset.properties.from.maximum;
         this.agSUWithDefaultValue['offset_from_min'] =  this.constraintSchema.schema.properties.sky.properties.transit_offset.properties.from.minimum;
         this.agSUWithDefaultValue['offset_to_max'] = this.constraintSchema.schema.properties.sky.properties.transit_offset.properties.to.maximum;
@@ -1398,50 +1403,8 @@ export class SchedulingSetCreate extends Component {
                             }
                         }
                     }, },
-                    {headerName: 'Offset Window From',field: 'offset_from',cellStyle: function(params) {
-                        if  (params.value){
-                            const maxValue = params.data.offset_from_max? params.data.offset_from_max:params.data.gdef_offset_from_max;
-                            const minValue = params.data.offset_from_min? params.data.offset_from_min:params.data.gdef_offset_from_min;
-                            if  (params.value === 'undefined' || params.value === ''){
-                                return { backgroundColor: ''};
-                            }
-                            if(params.value === "0"){
-                                return { backgroundColor: ''};
-                            }
-                            if (!Number(params.value)){
-                                return { backgroundColor: BG_COLOR};
-                            }
-                            else if ( Number(params.value) < minValue ||   Number(params.value) > maxValue) {
-                                return { backgroundColor: BG_COLOR};
-                            } else{
-                                return { backgroundColor: ''};
-                            }
-                        }  else  {
-                            return { backgroundColor: ''};
-                        }
-                    }, },
-                    {headerName: 'Offset Window To',field: 'offset_to', cellStyle: function(params) {
-                        const maxValue = params.data.offset_to_max? params.data.offset_to_max:params.data.gdef_offset_to_max;
-                        const minValue = params.data.offset_to_min? params.data.offset_to_min:params.data.gdef_offset_to_min;
-                        if  (params.value){
-                            if  (params.value === 'undefined' || params.value === ''){
-                                return { backgroundColor: ''};
-                            }
-                            if(params.value === "0"){
-                                return { backgroundColor: ''};
-                            }
-                            if ( !Number(params.value)){
-                                return { backgroundColor: BG_COLOR};
-                            }
-                            else if ( Number(params.value) < minValue ||   Number(params.value) > maxValue) {
-                                return { backgroundColor: BG_COLOR};
-                            } else{
-                                return { backgroundColor: ''};
-                            }
-                        }  else  {
-                            return { backgroundColor: ''};
-                        }
-                    }, },
+                    {headerName: 'Offset Window From',field: 'offset_from',cellRenderer: 'betweenRenderer',cellEditor: 'offsetTimeInputmask',valueSetter: 'newValueSetter',},
+                    {headerName: 'Offset Window To',field: 'offset_to', cellRenderer: 'betweenRenderer',cellEditor: 'offsetTimeInputmask',valueSetter: 'newValueSetter', },
                 ],
             });
             this.colKeyOrder.push('md_sun');
@@ -1681,18 +1644,24 @@ export class SchedulingSetCreate extends Component {
                                         errorMsg += column.colDef.headerName+", ";
                                     }
                                 } else if (column.colId === 'offset_from'){
-                                    if ( typeof rowData[column.colId] === 'undefined' || (rowData[column.colId] && isNaN(rowData[column.colId]))){
+                                    const tmpTime = _.split(rowData[column.colId], ":");
+                                    if ( typeof rowData[column.colId] === 'undefined' || 
+                                    (tmpTime.length !== 3 || isNaN(tmpTime[1]) || tmpTime[1]>59 || isNaN(tmpTime[2]) || tmpTime[2]>59)){
                                         isValidRow = false;
                                          errorMsg += column.colDef.headerName+", ";
-                                    } else if  ( Number(rowData[column.colId]) < rowData['offset_from_min'] ||   Number(rowData[column.colId]) > rowData['offset_from_max']) {
+                                       // column.colDef.cellStyle = { backgroundColor: BG_COLOR};
+                                       // rowNoColumn.colDef.cellStyle = { backgroundColor: BG_COLOR};
+                                    } else if ( UnitConverter.getHHmmssToSecs(rowData[column.colId]) < rowData['offset_from_min'] || UnitConverter.getHHmmssToSecs(rowData[column.colId]) > rowData['offset_from_max']) {
                                         isValidRow = false;
                                          errorMsg += column.colDef.headerName+", ";
                                     }
                                 } else if (column.colId === 'offset_to'){
-                                    if ( typeof rowData[column.colId] === 'undefined' || (rowData[column.colId] && isNaN(rowData[column.colId]))){
+                                    const tmpTime = _.split(rowData[column.colId], ":");
+                                    if ( typeof rowData[column.colId] === 'undefined' || 
+                                    (tmpTime.length !== 3 || tmpTime[1]>59 || tmpTime[2]>59)){
                                         isValidRow = false;
                                          errorMsg += column.colDef.headerName+", ";
-                                    } else if  ( Number(rowData[column.colId]) < rowData['offset_to_min'] ||   Number(rowData[column.colId]) > rowData['offset_to_max']) {
+                                    } else if  ( UnitConverter.getHHmmssToSecs(rowData[column.colId]) < rowData['offset_to_min'] ||   UnitConverter.getHHmmssToSecs(rowData[column.colId]) > rowData['offset_to_max']) {
                                         isValidRow = false;
                                          errorMsg += column.colDef.headerName+", ";
                                     }
@@ -1952,8 +1921,8 @@ export class SchedulingSetCreate extends Component {
         constraint.sky.min_distance = min_distance_res;
         
         let transit_offset_res = {};
-        transit_offset_res['from'] = +suRow.offset_from;
-        transit_offset_res['to'] = +suRow.offset_to;
+        transit_offset_res['from'] = UnitConverter.getHHmmssToSecs(suRow.offset_from);
+        transit_offset_res['to'] = UnitConverter.getHHmmssToSecs(suRow.offset_to);
         if  (transit_offset_res){
             constraint.sky.transit_offset= transit_offset_res;
         }
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/summary.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/summary.js
index af5de42019e732c35b3f7cbc6e9293aaa177deb4..087340e36268ebbdf5fc96479227a153ab48bb3b 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/summary.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/summary.js
@@ -11,7 +11,7 @@ import { Button } from "primereact/button";
 import AuthStore from '../../authenticate/auth.store';
 import AuthUtil from '../../utils/auth.util';
 import { CustomDialog } from '../../layout/components/CustomDialog';
-import { findAllByDisplayValue } from '@testing-library/dom';
+import UnitConverter from '../../utils/unit.converter';
 
 /**
  * Component to view summary of the scheduling unit with limited task details
@@ -27,6 +27,7 @@ export class SchedulingUnitSummary extends Component {
             editCheck:1,
             close:false,
             userrole: AuthStore.getState(),
+            constraintsTemplate : this.props.constraintsTemplate,
         };        
         this.constraintsOrder = ['scheduler', 'time', 'daily', 'sky'];
         this.closeSUDets = this.closeSUDets.bind(this);
@@ -164,15 +165,49 @@ export class SchedulingUnitSummary extends Component {
     async componentDidMount() {
         const promises = [  
             AuthUtil.getUserRolePermission()
-        ];       
+        ];
+        this.updateConstraintTemplate();   
         await Promise.all(promises).then(responses => {
             this.setState({userrole: responses[0],editCheck:1});
         });
     }
 
+    /**
+     * Add new fields for plus/minu value for offset (from & to)
+     * @param {*} constraintTemplate 
+     * @returns 
+     */
+     async updateConstraintTemplate() {
+        if (this.props.constraintsTemplate) {
+            let constraintTemplate = this.props.constraintsTemplate;
+            constraintTemplate.schema.properties.sky.properties.transit_offset.properties.from.default = 
+            UnitConverter.getSecsToHHmmssWithSign(this.props.constraintsTemplate.schema.properties.sky.properties.transit_offset.properties.from.default);
+            constraintTemplate.schema.properties.sky.properties.transit_offset.properties.to.default = 
+            UnitConverter.getSecsToHHmmssWithSign(this.props.constraintsTemplate.schema.properties.sky.properties.transit_offset.properties.to.default);
+            this.setState({constraintTemplate: constraintTemplate});
+        }
+    }
+
+    /**
+     * Format constraint field value for UI
+     * @param {*} scheduling_constraints_doc 
+     * @returns 
+     */
+     formatConstraintDocForUI(scheduleunit) {
+        if (scheduleunit.scheduling_constraints_doc) {
+            scheduleunit.scheduling_constraints_doc.sky.transit_offset.from = UnitConverter.getSecsToHHmmssWithSign(scheduleunit.scheduling_constraints_doc.sky.transit_offset.from);
+            scheduleunit.scheduling_constraints_doc.sky.transit_offset.to = UnitConverter.getSecsToHHmmssWithSign(scheduleunit.scheduling_constraints_doc.sky.transit_offset.to);
+        }
+        if (this.props.schedulingUnit) {
+            this.props.schedulingUnit.scheduling_constraints_doc.sky.transit_offset.from = UnitConverter.getSecsToHHmmssWithSign(this.props.schedulingUnit.scheduling_constraints_doc.sky.transit_offset.from);
+            this.props.schedulingUnit.scheduling_constraints_doc.sky.transit_offset.to = UnitConverter.getSecsToHHmmssWithSign(this.props.schedulingUnit.scheduling_constraints_doc.sky.transit_offset.to);
+        }
+        return scheduleunit;
+    }
+    
     render() {
         const permissions = this.state.userrole.userRolePermission.scheduleunit;        
-        const schedulingUnit = this.props.schedulingUnit;      
+        let schedulingUnit = _.cloneDeep(this.props.schedulingUnit);      
         const suTaskList = this.props.suTaskList;
         suTaskList.map(task => {
             task.typeValue = task.specifications_template.type_value;
@@ -180,6 +215,7 @@ export class SchedulingUnitSummary extends Component {
         });
         const constraintsTemplate = this.props.constraintsTemplate;       
         // After receiving output from the SchedulingConstraint editor order and format it to display
+        schedulingUnit = this.formatConstraintDocForUI(schedulingUnit);
         let constraintsDoc = schedulingUnit.scheduling_constraints_doc ? this.getOrderedConstraints(schedulingUnit.scheduling_constraints_doc,this.constraintsOrder) : null; 
         let disableBtn= this.state.showerror!==0 ?true: false;
         return (
@@ -305,8 +341,8 @@ export class SchedulingUnitSummary extends Component {
                             }
                         >                             
                         <SchedulingConstraints
-                            constraintTemplate={constraintsTemplate}
-                            initValue={schedulingUnit.scheduling_constraints_doc}
+                            constraintTemplate={this.state.constraintsTemplate}
+                            initValue={this.props.schedulingUnit.scheduling_constraints_doc}
                             callback={this.setConstraintsEditorOutput}                                                                     
                         />                                      
                     </Dialog>
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/list.tabs.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/list.tabs.js
index db0997e9693b03850e3ba47b7bd6fe8606a94bf0..95ffc42ae4ba635efb3cb198bfa85fe5dd99a0a4 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/list.tabs.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/list.tabs.js
@@ -30,6 +30,7 @@ class TimelineListTabs extends Component {
         this.suListFilterCallback = this.suListFilterCallback.bind(this);
         this.taskListFilterCallback = this.taskListFilterCallback.bind(this);
         this.reservListFilterCallback = this.reservListFilterCallback.bind(this);
+        this.unschedulableCallback = this.unschedulableCallback.bind(this);
         this.getTaskList = this.getTaskList.bind(this);
         this.getSUFilterOptions = this.getSUFilterOptions.bind(this);
         this.getTaskFilterOptions = this.getTaskFilterOptions.bind(this);
@@ -136,7 +137,16 @@ class TimelineListTabs extends Component {
         this.filteredReservs = filteredData;
         this.props.suListFilterCallback(this.filteredSUB, this.filteredTasks, filteredData);
     }
-    
+
+    /**
+     * Callback function to pass the filtered data for all table data to the parent component to display in the timeline even if the 
+     * selected tab is unscedulable.
+     * @param {Array} filteredData - Array of unschedulable SUB rows
+     */
+    unschedulableCallback(filteredData) {
+        this.props.suListFilterCallback(this.filteredSUB, this.filteredTasks, this.filteredReservs);
+    }
+        
     /**
      * Child Component to display the status log column value with icon and show the dialog on clicking it.
      * @param {Object} task 
@@ -300,7 +310,7 @@ class TimelineListTabs extends Component {
                         showTopTotal={false}
                         showGlobalFilter={true}
                         showColumnFilter={true}
-                        // filterCallback={this.suListFilterCallback}
+                        filterCallback={this.unschedulableCallback}
                         lsKeySortColumn={"UnschedulableListSortColumn"}
                         toggleBySorting={(sortData) => this.storeSortingColumn(`${this.props.viewName}_UnschedulableListSortColumn`, sortData)}
                         pageUpdated={this.pageUpdated}
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 5ba3e8fc679a215a1dd82935e2ce4faa588bb09a..13c330939f98b6368df2dbd86aced0eb8fd0ea53 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/view.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/view.js
@@ -192,8 +192,12 @@ export class TimelineView extends Component {
                     })
                 }
             }
-        }       
-       UnitConversion.degreeToRadians(constStrategy.sky);
+        }
+        if (constStrategy.sky.transit_offset) {
+            constStrategy.sky.transit_offset.from = UnitConversion.getHHmmssToSecs(constStrategy.sky.transit_offset.from);
+            constStrategy.sky.transit_offset.to = UnitConversion.getHHmmssToSecs(constStrategy.sky.transit_offset.to);
+        }
+        UnitConversion.degreeToRadians(constStrategy.sky);
 
        // getConstraintsEditorOutputService - service call  is done for getting updated blueprint id
        const bluePrintValue = await ScheduleService.getConstraintsEditorOutputService(id);      
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 81d52efca2e8b353401e38e6a544ad11e2178d01..926b782e3f2c1101d0d8f28631f0a6d6097d828b 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
@@ -181,8 +181,12 @@ export class WeekTimelineView extends Component {
                     })
                 }
             }
-        }       
-       UnitConversion.degreeToRadians(constStrategy.sky);
+        }
+        if (constStrategy.sky.transit_offset) {
+            constStrategy.sky.transit_offset.from = UnitConversion.getHHmmssToSecs(constStrategy.sky.transit_offset.from);
+            constStrategy.sky.transit_offset.to = UnitConversion.getHHmmssToSecs(constStrategy.sky.transit_offset.to);
+        }
+        UnitConversion.degreeToRadians(constStrategy.sky);
 
        // getConstraintsEditorOutputService - service call  is done for getting updated blueprint id
        const bluePrintValue = await ScheduleService.getConstraintsEditorOutputService(id);      
@@ -1342,7 +1346,7 @@ export class WeekTimelineView extends Component {
                                     itemClickCallback={this.onItemClick}
                                     itemMouseOverCallback={this.onItemMouseOver}
                                     itemMouseOutCallback={this.onItemMouseOut}
-                                    sidebarWidth={150}
+                                    sidebarWidth={175}
                                     stackItems={true}
                                     startTime={moment.utc(this.state.currentUTC).hour(0).minutes(0).seconds(0)}
                                     endTime={moment.utc(this.state.currentUTC).hour(23).minutes(59).seconds(59)}
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 b5384aa4d05b406bb5a5e7237688f617711c3cdf..b6684a162480a97b754ef2aa9cc10c6fe18abcd8 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/services/schedule.service.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/services/schedule.service.js
@@ -117,6 +117,21 @@ const ScheduleService = {
             console.error('[schedule.services.getSchedulingUnitsExtendedWithFilter]',error);
         }
         return response;
+    },
+    getExpandedSchedulingUnit: async function(type, id, expand, fields) {
+        let schedulingUnit = null;
+        try {
+            let api = `/api/scheduling_unit_${type}/${id}/?`;
+            api += (expand === '')? '' : 'expand='+expand+'&';
+            api += (!fields || fields === '')? '' : 'fields='+fields+'&';
+            const response = await axios.get(api);
+            schedulingUnit = response.data;
+        }   catch(error) {
+            console.error('[schedule.services.getSchedulingUnitsExpandWithFilter]',error);
+        }
+        return schedulingUnit
+
+
     },
     getSchedulingUnitExtended: async function (type, id, ignoreRef){
         if (type === "constraints") {
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/utils/unit.converter.js b/SAS/TMSS/frontend/tmss_webapp/src/utils/unit.converter.js
index dc72950df943ac70367d8f5d5a3763f194dbc79f..345e6adbdfc27cbe75bfa9faaa768119b9e47260 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/utils/unit.converter.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/utils/unit.converter.js
@@ -61,19 +61,34 @@ const UnitConverter = {
         let stopTime = moment(stopdate).unix();
         return UnitConverter.getSecsToDDHHmmss(stopTime - startTime);
     },
+    getSecsToHHmmssWithSign: function (seconds) {
+        var prefix = '';
+        if (!isNaN(seconds)) {
+            if (seconds<0) {
+                prefix = '-';
+            }
+            seconds = prefix+this.getSecsToHHmmss(seconds);
+        }
+        return seconds;
+    },
     getSecsToHHmmss: function (seconds) {
-        if (seconds >= 0) {
+        if (!isNaN(seconds)) {
+            seconds = Math.abs(seconds);
             const hh = Math.floor(seconds / 3600);
             const mm = Math.floor((seconds - hh * 3600) / 60);
             const ss = +((seconds - (hh * 3600) - (mm * 60)) / 1);
-            return (hh < 10 ? `0${hh}` : `${hh}`) + ':' + (mm < 10 ? `0${mm}` : `${mm}`) + ':' + (ss < 10 ? `0${ss}` : `${ss}`);
+            let retStr = (hh < 10 ? `0${hh}` : `${hh}`) + ':' + (mm < 10 ? `0${mm}` : `${mm}`) + ':' + (ss < 10 ? `0${ss}` : `${ss}`);
+            return retStr;
         }
         return seconds;
     },
-    getHHmmssToSecs: function (seconds) {
-        if (seconds) {
-            const strSeconds = _.split(seconds, ":");
-            return strSeconds[0] * 3600 + strSeconds[1] * 60 + Number(strSeconds[2]);
+    getHHmmssToSecs: function (time) {
+        if (time) {
+            time = _.trim(time);
+            let prefix = _.startsWith(time, '-')?-1:1;
+            time = time.replace("-","").replace("+","");
+            const strSeconds = _.split(time, ":");
+            return prefix * (strSeconds[0] * 3600 + strSeconds[1] * 60 + Number(strSeconds[2]));
         }
         return 0;
     },
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/utils/validator.js b/SAS/TMSS/frontend/tmss_webapp/src/utils/validator.js
index 4453a7ceca38bf1dfa7d24a9ef25df4d499f1e1d..a11cde4f0e02ca0c3e3e16cf046abcb0d5a605d2 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/utils/validator.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/utils/validator.js
@@ -1,4 +1,5 @@
 import UnitConverter from "./unit.converter";
+import _ from 'lodash';
 
 const Validator = {
     validateTime(value) {
@@ -62,8 +63,7 @@ const Validator = {
             }   else {
                 var timeFormat = /^([0-9]|[0-1][0-9]|[0-2][0-3]):([0-9]|[0-5][0-9]):([0-9]|[0-5][0-9])$/;
                 isValid = timeFormat.test(time);
-            }
-            
+            }            
         }   else {
             isValid = false;
         }
@@ -96,7 +96,34 @@ const Validator = {
         }   else {
             return false;
         }
-    }
+    },
+    validateTransitOffset(schema, jsonOutput, error, path) {
+        const tmpTime = _.split(jsonOutput, ":");
+        if (jsonOutput.length === 0 && schema.required === true)   {
+            error.push({
+                message:`Transit Offset - ${schema.title} is required. Time format should be [+/- Hours:Minutes:Seconds]. eg. '-23:59:59', '+20:23:25', '15:45:45'`,
+                path:path,
+                property:'validationType',
+            });
+        }   
+        //here the isValidHHmmss() valiadtion function not used because it requires only MM:SS validation and the hours may define more than 23
+        else if (tmpTime.length !== 3 || tmpTime[1]>59 || tmpTime[1].trim() === '' || tmpTime[2]>59 || tmpTime[2].trim()  === '') {
+            error.push({
+                message:"Invalid time format. Time format should be [+/- Hours:Minutes:Seconds]. eg. '-23:59:59', '+20:23:25', '15:45:45'",
+                path:path,
+                property:'validationType',
+            });
+        }   else {
+            let value = UnitConverter.getHHmmssToSecs(jsonOutput);
+            if (isNaN(value) || (value < schema.minimum || value > schema.maximum)) {
+                error.push({
+                    message:'Time must be between '+((schema.minimum<0)?'-':'')+UnitConverter.getSecsToHHmmss(schema.minimum)+' and '+((schema.maximum<0)?'-':'')+UnitConverter.getSecsToHHmmss(schema.maximum),
+                    path:path,
+                    property:'validationType',
+                });
+            }
+        }
+    },
 };
 
 export default Validator;