diff --git a/SAS/TMSS/backend/services/scheduling/lib/constraints/template_constraints_v1.py b/SAS/TMSS/backend/services/scheduling/lib/constraints/template_constraints_v1.py
index 550efab2b7be2627304ce24c24f4cf95cd5cb9c0..910fc96e2c37ba32e21546ed87935083b3bba7a9 100644
--- a/SAS/TMSS/backend/services/scheduling/lib/constraints/template_constraints_v1.py
+++ b/SAS/TMSS/backend/services/scheduling/lib/constraints/template_constraints_v1.py
@@ -158,14 +158,23 @@ def can_run_within_timewindow_with_time_constraints(scheduling_unit: models.Sche
              constraints are met over the runtime of the observation, else False.
     """
     main_observation_task_name = get_target_observation_task_name_from_requirements_doc(scheduling_unit)
-    duration = timedelta(
-        seconds=scheduling_unit.requirements_doc['tasks'][main_observation_task_name]['specifications_doc']['duration'])
-    window_lower_bound = lower_bound
-    while window_lower_bound + duration < upper_bound:
-        window_upper_bound = window_lower_bound + duration
-        if can_run_anywhere_within_timewindow_with_time_constraints(scheduling_unit, window_lower_bound, window_upper_bound):
-            return True
-        window_lower_bound += min(timedelta(hours=1), upper_bound - window_lower_bound)
+    constraints = scheduling_unit.draft.scheduling_constraints_doc
+
+    # Check the 'at' constraint and then only check can_run_anywhere for the single possible time window
+    if 'at' in constraints['time']:
+        at = parser.parse(constraints['time']['at'], ignoretz=True)
+        if (at >= lower_bound and at + scheduling_unit.duration <= upper_bound):    # todo: suggestion: use scheduling_unit.requirements_doc['tasks']['Observation']['specifications_doc']['duration']
+            return can_run_anywhere_within_timewindow_with_time_constraints(scheduling_unit, lower_bound=at,
+                                                                            upper_bound=at + scheduling_unit.duration)
+    else:
+        duration = timedelta(
+            seconds=scheduling_unit.requirements_doc['tasks'][main_observation_task_name]['specifications_doc']['duration'])
+        window_lower_bound = lower_bound
+        while window_lower_bound + duration <= upper_bound:
+            window_upper_bound = window_lower_bound + duration
+            if can_run_anywhere_within_timewindow_with_time_constraints(scheduling_unit, window_lower_bound, window_upper_bound):
+                return True
+            window_lower_bound += min(timedelta(hours=1), upper_bound - window_lower_bound)
 
     return False
 
@@ -176,25 +185,21 @@ def can_run_anywhere_within_timewindow_with_time_constraints(scheduling_unit: mo
     i.e. the time constraints must be met over the full time window.
     :return: True if all time constraints are met over the entire time window, else False.
     """
-    can_run_at = True
     can_run_before = True
     can_run_with_after = True
     can_run_between = True
     can_run_not_between = True
     constraints = scheduling_unit.draft.scheduling_constraints_doc
 
-    # TODO TMSS-672 Move to can_run_within and make logic correct
-    if has_manual_scheduler_constraint(scheduling_unit):
-        at = parser.parse(constraints['time']['at'], ignoretz=True)
-        can_run_at = (at >= lower_bound and at+scheduling_unit.duration <= upper_bound) # todo: suggestion: use scheduling_unit.requirements_doc['tasks']['Observation']['specifications_doc']['duration']
-
+    # given time window needs to end before constraint
     if 'before' in constraints['time']:
         before = parser.parse(constraints['time']['before'], ignoretz=True)
-        can_run_before = (before <= upper_bound-scheduling_unit.duration)   # todo: suggestion: use scheduling_unit.requirements_doc['tasks']['Observation']['specifications_doc']['duration']
+        can_run_before = (upper_bound < before)
 
+    # given time window needs to start after constraint
     if 'after' in constraints['time']:
         after = parser.parse(constraints['time']['after'], ignoretz=True)
-        can_run_with_after = (lower_bound >= after)
+        can_run_with_after = (lower_bound > after)
 
     # Run within one of these time windows
     if 'between' in constraints['time']:
@@ -202,9 +207,9 @@ def can_run_anywhere_within_timewindow_with_time_constraints(scheduling_unit: mo
         for between in constraints['time']['between']:
             time_from = parser.parse(between["from"], ignoretz=True)
             time_to = parser.parse(between["to"], ignoretz=True)
-            if time_from >= lower_bound and time_to <= upper_bound:
+            if time_from <= lower_bound and time_to >= upper_bound:
                 can_run_between = True
-                break  # something inside the boundary so True and don't look any further
+                break  # constraint window completely covering the boundary, so True and don't look any further
             else:
                 can_run_between = False
 
@@ -216,11 +221,11 @@ def can_run_anywhere_within_timewindow_with_time_constraints(scheduling_unit: mo
             time_to = parser.parse(not_between["to"], ignoretz=True)
             if time_from <= upper_bound and time_to >= lower_bound:
                 can_run_not_between = False
-                break  # something outside the boundary so False and don't look any further
+                break  # constraint window at least partially inside the boundary, so False and don't look any further
             else:
                 can_run_not_between = True
 
-    return can_run_at & can_run_before & can_run_with_after & can_run_between & can_run_not_between
+    return can_run_before & can_run_with_after & can_run_between & can_run_not_between
 
 
 def can_run_within_timewindow_with_sky_constraints(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime, upper_bound: datetime) -> bool:
@@ -233,7 +238,7 @@ def can_run_within_timewindow_with_sky_constraints(scheduling_unit: models.Sched
             if 'duration' in task['specifications_doc']:
                 duration = timedelta(seconds=task['specifications_doc']['duration'])
                 window_lower_bound = lower_bound
-                while window_lower_bound + duration < upper_bound:
+                while window_lower_bound + duration <= upper_bound:
                     window_upper_bound = window_lower_bound + duration
                     if can_run_anywhere_within_timewindow_with_sky_constraints(scheduling_unit, window_lower_bound, window_upper_bound):
                         return True
@@ -309,7 +314,7 @@ def get_earliest_possible_start_time(scheduling_unit: models.SchedulingUnitBluep
     main_observation_task_name = get_target_observation_task_name_from_requirements_doc(scheduling_unit)
     duration = timedelta(seconds=scheduling_unit.requirements_doc['tasks'][main_observation_task_name]['specifications_doc']['duration'])
     try:
-        if has_manual_scheduler_constraint(scheduling_unit) and 'at' in constraints['time']:
+        if 'at' in constraints['time']:
             at = parser.parse(constraints['time']['at'], ignoretz=True)
             return max(lower_bound, at)
 
@@ -383,10 +388,10 @@ def compute_scores(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound:
     # TODO: TMSS-244 (and more?), compute score using the constraints in constraints['time']
     # TODO: TMSS-245 TMSS-250 (and more?),  compute score using the constraints in constraints['sky']
 
-    # for now (as a proof of concept and sort of example), just return 1's
+    # for now (as a proof of concept and sort of example), just return 1's. Return 1000 (placeholder value, change later) if the 'at' constraint is in, so it gets prioritised.
     scores = {'daily': 1.0,
-              'time': 1.0,
-              'sky': 1.0 }
+              'time': 1000.0 if ('at' in constraints['time'] and constraints['time']['at'] is not None) else 1.0,
+              'sky': 1.0}
 
     # add "common" scores which do not depend on constraints, such as project rank and creation date
     # TODO: should be normalized!
diff --git a/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py b/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py
index e8fadb2c6085117007f7913c8ecee0fa3808b434..bcd9f1fb6aa1d3dbbed8334c186dd3f53cb1e161 100755
--- a/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py
+++ b/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py
@@ -33,6 +33,7 @@ if skip_integration_tests():
 TEST_UUID = uuid.uuid1()
 
 from datetime import datetime, timedelta
+from lofar.common.datetimeutils import round_to_second_precision
 from lofar.common.json_utils import get_default_json_object_for_schema, add_defaults_to_json_object_for_schema
 from lofar.messaging.messagebus import TemporaryExchange, BusListenerJanitor
 
@@ -136,6 +137,76 @@ class TestDynamicScheduling(TestCase):  # Note: we use django.test.TestCase inst
                                                          scheduling_constraints_doc=constraints,
                                                          scheduling_constraints_template=constraints_template)
 
+    def test_simple_observation_with_at_constraint(self):
+        """
+        Test a simple observation with the 'at' constraint
+        """
+        scheduling_set = models.SchedulingSet.objects.create(**SchedulingSet_test_data())
+        scheduling_unit_draft = self.create_simple_observation_scheduling_unit('scheduling_unit for at constraint', scheduling_set=scheduling_set)
+        # Clear constraints
+        scheduling_unit_draft.scheduling_constraints_doc['sky'] = {}
+        scheduling_unit_draft.scheduling_constraints_doc['time']["between"] = []
+        scheduling_unit_draft.scheduling_constraints_doc['time']["not_between"] = []
+        scheduling_unit_draft.scheduling_constraints_doc['time'].pop('at', None)
+        scheduling_unit_draft.scheduling_constraints_doc['time'].pop("before", None)
+        scheduling_unit_draft.scheduling_constraints_doc['time'].pop('after', None)
+        # Set at constraint
+        at = round_to_second_precision(datetime.utcnow() + timedelta(minutes=10))
+        scheduling_unit_draft.scheduling_constraints_doc['time']['at'] = at.isoformat()
+        scheduling_unit_draft.save()
+        scheduling_unit_blueprint = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft)
+
+        scheduled_scheduling_unit = do_dynamic_schedule()
+
+        # Assert the scheduling_unit has been scheduled and assert is has been scheduled at "at" timestamp
+        self.assertIsNotNone(scheduled_scheduling_unit)
+        self.assertEqual(scheduled_scheduling_unit.id, scheduling_unit_blueprint.id)
+        self.assertEqual(scheduled_scheduling_unit.status, 'scheduled')
+        self.assertEqual(scheduled_scheduling_unit.start_time, at)
+
+    def test_n_simple_observations_one_at_constraint(self):
+        """
+        Test n simple observations where only one of them has an 'at' constraint
+        """
+        n = 5   # No of SU to be created
+        target = 4  # SU id to be within the 'at' constraint
+        target_scheduling_unit_blueprint = None # SU which will be our target
+
+        # Create constraints to be assigned to all of the scheduling_units
+        from_timestamp = round_to_second_precision(datetime.utcnow())
+        to_timestamp = round_to_second_precision(datetime.utcnow() + timedelta(hours=12))
+        between_constraints = [{"from": from_timestamp.isoformat(), "to": to_timestamp.isoformat()},]
+        # Create at constraint to be assigned only to one of the scheduling_units
+        at = round_to_second_precision((datetime.utcnow() + timedelta(minutes=30)))
+
+        # Create n scheduling_units and set the proper constraints
+        for su in range(1, n+1):
+            scheduling_set = models.SchedulingSet.objects.create(**SchedulingSet_test_data())
+            scheduling_unit_draft = self.create_simple_observation_scheduling_unit('scheduling_unit %s' % su,
+                                                                                   scheduling_set=scheduling_set)
+            # Clear constraints
+            scheduling_unit_draft.scheduling_constraints_doc['sky'] = {}
+            scheduling_unit_draft.scheduling_constraints_doc['time']["between"] = between_constraints
+            scheduling_unit_draft.scheduling_constraints_doc['time']["not_between"] = []
+            scheduling_unit_draft.scheduling_constraints_doc['time'].pop("before", None)
+            scheduling_unit_draft.scheduling_constraints_doc['time'].pop('after', None)
+            scheduling_unit_draft.scheduling_constraints_doc['time'].pop("at", None)
+            scheduling_unit_draft.save()
+            if su == target:    # Only scheduling_unit with id 'target' is set within an 'at' constraint
+                scheduling_unit_draft.scheduling_constraints_doc['time']['at'] = at.isoformat()
+                scheduling_unit_draft.save()
+                target_scheduling_unit_blueprint = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft)
+            else:
+                create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft)
+
+        scheduled_scheduling_unit = do_dynamic_schedule()
+
+        # Assert the 'target' scheduling_unit has been scheduled with priority and assert it is has been scheduled at "at" timestamp
+        self.assertIsNotNone(scheduled_scheduling_unit)
+        self.assertEqual(scheduled_scheduling_unit.id, target_scheduling_unit_blueprint.id)
+        self.assertEqual(scheduled_scheduling_unit.status, 'scheduled')
+        self.assertEqual(scheduled_scheduling_unit.start_time, at)
+
     @unittest.skip("FIX TEST, skipping it for now, see TODO comment in assign_start_stop_times_to_schedulable_scheduling_units")
     def test_three_simple_observations_no_constraints_different_project_priority(self):
         scheduling_unit_draft_low = self.create_simple_observation_scheduling_unit("scheduling unit low", scheduling_set=self.scheduling_set_low)
@@ -179,6 +250,7 @@ class TestDynamicScheduling(TestCase):  # Note: we use django.test.TestCase inst
         self.assertGreaterEqual(scheduling_unit_blueprint_medium.start_time - scheduling_unit_blueprint_high.stop_time, DEFAULT_INTER_OBSERVATION_GAP)
         self.assertGreaterEqual(scheduling_unit_blueprint_low.start_time - scheduling_unit_blueprint_medium.stop_time, DEFAULT_INTER_OBSERVATION_GAP)
 
+    @unittest.skip("Skipped because the corrected 'before' constraint broke scheduler behavior. See TMSS-705")
     def test_time_bound_unit_wins_even_at_lower_priority(self):
         # create two schedule units, one with high one with low prio.
         # first create them without any further constraints, and check if high prio wins.
@@ -198,7 +270,7 @@ class TestDynamicScheduling(TestCase):  # Note: we use django.test.TestCase inst
         self.assertEqual(scheduling_unit_blueprint_high.id, best_scored_scheduling_unit.scheduling_unit.id)
 
         #now update the low prio unit with a time constraint, "forcing" it to be run in a very thight upcoming time window.
-        scheduling_unit_draft_low.scheduling_constraints_doc['time'] = { 'before': (now+scheduling_unit_draft_low.duration).isoformat()+'Z' }
+        scheduling_unit_draft_low.scheduling_constraints_doc['time'] = { 'before': (now+scheduling_unit_draft_low.duration+timedelta(seconds=10)).isoformat()+'Z' }
         scheduling_unit_draft_low.save()
         scheduling_unit_blueprint_low.refresh_from_db()
 
@@ -206,22 +278,20 @@ class TestDynamicScheduling(TestCase):  # Note: we use django.test.TestCase inst
         best_scored_scheduling_unit = find_best_next_schedulable_unit([scheduling_unit_blueprint_low, scheduling_unit_blueprint_high], now, tomorrow)
 
         # now we expect the scheduling_unit with the lowest project rank to be scheduled first because it can only run within this limited timewindow
-        self.assertEqual(scheduling_unit_draft_low.id, best_scored_scheduling_unit.scheduling_unit.id)
+        self.assertEqual(scheduling_unit_blueprint_low.id, best_scored_scheduling_unit.scheduling_unit.id)
 
 
         #  update the low prio unit. enlarge the time window constraint a bit, so both low and high prio units can fit
         # this should result that the high prio goes first, and the low prio (which now fits as well) goes second
-        scheduling_unit_draft_low.scheduling_constraints_doc['time'] = \
-            { 'before': (now+scheduling_unit_draft_low.duration+scheduling_unit_draft_high.duration).isoformat()+'Z' }
+        scheduling_unit_draft_low.scheduling_constraints_doc['time'] = { 'before': (now+scheduling_unit_draft_low.duration+scheduling_unit_draft_high.duration+timedelta(seconds=10)).isoformat()+'Z' }
         scheduling_unit_draft_low.save()
         scheduling_unit_blueprint_low.refresh_from_db()
 
         # call the method-under-test.
         best_scored_scheduling_unit = find_best_next_schedulable_unit([scheduling_unit_blueprint_low, scheduling_unit_blueprint_high], now, tomorrow)
 
-        # now we expect the scheduling_unit with the lowest project rank to be scheduled first because it can only
-        # run within this limited timewindow
-        self.assertEqual(scheduling_unit_blueprint_low.id, best_scored_scheduling_unit.scheduling_unit.id)
+        # now we again expect the scheduling_unit with the higher project rank to be scheduled first
+        self.assertEqual(scheduling_unit_blueprint_high.id, best_scored_scheduling_unit.scheduling_unit.id)
 
         # call the method-under-test again but search after first unit (should return low prio unit)
         stop_time_of_first =  best_scored_scheduling_unit.start_time + best_scored_scheduling_unit.scheduling_unit.duration
@@ -739,7 +809,7 @@ class TestSkyConstraints(unittest.TestCase):
                                                    {"rise": datetime(2020, 1, 1, 8, 0, 0), "set": datetime(2020, 1, 1, 12, 30, 0), "always_above_horizon": False, "always_below_horizon": False}]}
         self.target_rise_and_set_data_always_above = {"CS002": [{"rise": None, "set": None, "always_above_horizon": True, "always_below_horizon": False}]}
         self.target_rise_and_set_data_always_below = {"CS002": [{"rise": None, "set": None, "always_above_horizon": False, "always_below_horizon": True}]}
-        
+
         self.target_rise_and_set_patcher = mock.patch('lofar.sas.tmss.services.scheduling.constraints.template_constraints_v1.coordinates_timestamps_and_stations_to_target_rise_and_set')
         self.target_rise_and_set_mock = self.target_rise_and_set_patcher.start()
         self.target_rise_and_set_mock.return_value = self.target_rise_and_set_data
@@ -760,58 +830,40 @@ class TestSkyConstraints(unittest.TestCase):
         timestamp = datetime(2020, 1, 1, 10, 0, 0)
         returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
         self.assertFalse(returned_value)
-        
-    # min_target_elevation
 
-    def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_min_target_elevation_constraint_returns_true(self):
-        self.target_rise_and_set_mock.return_value = self.target_rise_and_set_data
-
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'min_target_elevation': 0.1}
-        self.scheduling_unit_blueprint.save()
-        timestamp = datetime(2020, 1, 1, 10, 0, 0)  # target sets after obs ends (mocked response)
-        returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
-        self.assertTrue(returned_value)
-
-    def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_min_target_elevation_when_target_always_above_returns_true(self):
-        self.target_rise_and_set_mock.return_value = self.target_rise_and_set_data_always_above
+    # min_target_elevation
 
+    def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_min_target_elevation_constraint_returns_true_when_met(self):
         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'min_target_elevation': 0.1}
         self.scheduling_unit_blueprint.save()
-        timestamp = datetime(2020, 1, 1, 10, 0, 0)  # target is always up (mocked response)
+        timestamp = datetime(2020, 1, 1, 10, 0, 0)
         returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
         self.assertTrue(returned_value)
 
-    def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_min_target_elevation_constraint_returns_false(self):
-        self.target_rise_and_set_mock.return_value = self.target_rise_and_set_data
-
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'min_target_elevation': 0.1}
-        self.scheduling_unit_blueprint.save()
-        timestamp = datetime(2020, 1, 1, 11, 0, 0)  # target sets before obs ends (mocked response)
-        returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
-        self.assertFalse(returned_value)
-
-    def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_min_target_elevation_when_target_is_always_below_returns_false(self):
-        self.target_rise_and_set_mock.return_value = self.target_rise_and_set_data_always_below
-
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'min_target_elevation': 0.1}
+    def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_min_target_elevation_constraint_returns_false_when_not_met(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'min_target_elevation': 0.2}
         self.scheduling_unit_blueprint.save()
-        timestamp = datetime(2020, 1, 1, 10, 0, 0)  # target is never up (mocked response)
+        timestamp = datetime(2020, 1, 1, 11, 0, 0)
         returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
         self.assertFalse(returned_value)
 
 
-
-
 class TestTimeConstraints(TestCase):
     """
     Tests for the time constraint checkers used in dynamic scheduling with different boundaries
     Possible time constraints are
+    - at
     - after
     - before
     - between (one or more 'from-to')
     - not between (one or more 'from-to')
     """
 
+    def add_time_at_constraint(self, at_timestamp):
+        lst_at_constraint = self.scheduling_unit_blueprint.draft.scheduling_constraints_doc
+        lst_at_constraint['time']['at'] = at_timestamp.isoformat()
+        self.scheduling_unit_blueprint.save()
+
     def add_time_between_constraint(self, from_timestamp, to_timestamp):
         lst_between_constraints = self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["between"]
         time_constraint_dict = {"from": from_timestamp.isoformat(), "to": to_timestamp.isoformat()}
@@ -824,6 +876,13 @@ class TestTimeConstraints(TestCase):
         lst_between_constraints.append(time_constraint_dict)
         self.scheduling_unit_blueprint.save()
 
+    def clear_time_constraints(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["between"] = []
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["not_between"] = []
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time'].pop('at', None)
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time'].pop("before", None)
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time'].pop('after', None)
+
     def setUp(self) -> None:
         # scheduling unit
         self.obs_duration = 120 * 60
@@ -834,113 +893,256 @@ class TestTimeConstraints(TestCase):
                                     obs_duration=self.obs_duration)
         self.scheduling_unit_blueprint = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft)
 
+    # 'after' constraint
+
+    def test_can_run_anywhere_after_returns_true(self):
+
+        # Set datetime constraints before lower_bound
+        self.clear_time_constraints()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 11, 0, 0).isoformat()
+        self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                            datetime(2020, 1, 1, 12, 0, 0),
+                                                                            datetime(2020, 1, 2, 12, 0, 0)))
+
     def test_can_run_anywhere_after_returns_false(self):
+
+        # Set datetime constraints equal to lower_bound
+        self.clear_time_constraints()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 12, 0, 0).isoformat()
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                            datetime(2020, 1, 1, 12, 0, 0),
+                                                                            datetime(2020, 1, 2, 12, 0, 0)))
+
         # Set datetime constraints after lower_bound
+        self.clear_time_constraints()
         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 13, 0, 0).isoformat()
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                              datetime(2020, 1, 1, 12, 0, 0),
                                                                              datetime(2020, 1, 2, 12, 0, 0)))
 
         # Set datetime constraints to upper_bound
+        self.clear_time_constraints()
         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 2, 12, 0, 0).isoformat()
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                              datetime(2020, 1, 1, 12, 0, 0),
                                                                              datetime(2020, 1, 2, 12, 0, 0)))
 
-    def test_can_run_anywhere_after_returns_true(self):
-        # Set datetime constraints before lower_bound
+        # Set datetime constraints after upper_bound
+        self.clear_time_constraints()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 2, 13, 0, 0).isoformat()
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                             datetime(2020, 1, 1, 12, 0, 0),
+                                                                             datetime(2020, 1, 2, 12, 0, 0)))
+
+    def test_can_run_within_after_returns_false(self):
+
+        # Set datetime constraints before lower bounds, but with too short window for obs duration
+        self.clear_time_constraints()
         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 11, 0, 0).isoformat()
-        self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+        self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                            datetime(2020, 1, 1, 12, 0, 0),
+                                                                            datetime(2020, 1, 1, 13, 0, 0)))
+
+        # Set datetime constraints after lower bounds, and with too little space left in window for obs duration
+        self.clear_time_constraints()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 14, 0, 0).isoformat()
+        self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                            datetime(2020, 1, 1, 12, 0, 0),
+                                                                            datetime(2020, 1, 1, 15, 0, 0)))
+
+    def test_can_run_within_after_returns_true(self):
+
+        # Set datetime constraints before lower bounds, and with sufficient window for obs duration
+        self.clear_time_constraints()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 11, 0, 0).isoformat()
+        self.assertTrue(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                            datetime(2020, 1, 1, 12, 0, 0),
+                                                                            datetime(2020, 1, 1, 14, 0, 0)))
+
+        # Set datetime constraints after lower bounds, but with sufficient space left in window for obs duration
+        self.clear_time_constraints()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 13, 0, 0).isoformat()
+        self.assertTrue(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                            datetime(2020, 1, 1, 12, 0, 0),
+                                                                            datetime(2020, 1, 1, 16, 0, 0)))
+
+    # 'before' constraint
+
+    def test_can_run_anywhere_before_returns_false(self):
+
+        # Set datetime constraints before lower_bound
+        self.clear_time_constraints()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 11, 0, 0).isoformat()
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                             datetime(2020, 1, 1, 12, 0, 0),
                                                                             datetime(2020, 1, 2, 12, 0, 0)))
+
         # Set datetime constraints equal to lower_bound
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 12, 0, 0).isoformat()
-        self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+        self.clear_time_constraints()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 12, 0, 0).isoformat()
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                             datetime(2020, 1, 1, 12, 0, 0),
                                                                             datetime(2020, 1, 2, 12, 0, 0)))
 
-    def test_can_run_anywhere_before_returns_false(self):
-        # Set datetime constraints after upper_bound
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 13, 0, 0).isoformat()
+        # Set datetime constraints after lower_bound
+        self.clear_time_constraints()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 13, 0, 0).isoformat()
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                              datetime(2020, 1, 1, 12, 0, 0),
                                                                              datetime(2020, 1, 2, 12, 0, 0)))
         # Set datetime constraints equal to upper_bound
+        self.clear_time_constraints()
         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 12, 0, 0).isoformat()
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                              datetime(2020, 1, 1, 12, 0, 0),
                                                                              datetime(2020, 1, 2, 12, 0, 0)))
-        # Set datetime constraints equal to upper_bound - duration + 1 sec
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = \
-            (datetime(2020, 1, 2, 12, 0, 0) - self.scheduling_unit_blueprint.duration + timedelta(seconds=1)).isoformat()
-        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
-                                                                            datetime(2020, 1, 1, 12, 0, 0),
-                                                                            datetime(2020, 1, 2, 12, 0, 0)))
+
 
     def test_can_run_anywhere_before_returns_true(self):
-        # Set datetime constraints far before upper_bound (lower_bound)
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 12, 0, 0).isoformat()
+
+        # Set datetime constraints after upper_bound
+        self.clear_time_constraints()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 13, 0, 0).isoformat()
         self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                             datetime(2020, 1, 1, 12, 0, 0),
                                                                             datetime(2020, 1, 2, 12, 0, 0)))
-        # Set datetime constraints equal to upper_bound - duration
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = \
-            (datetime(2020, 1, 2, 12, 0, 0) - self.scheduling_unit_blueprint.duration).isoformat()
-        self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+
+    def test_can_run_within_before_returns_false(self):
+
+        # Set datetime constraints after upper bound, but with too short window for obs duration
+        self.clear_time_constraints()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 13, 0, 0).isoformat()
+        self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                            datetime(2020, 1, 2, 11, 0, 0),
+                                                                            datetime(2020, 1, 2, 12, 0, 0)))
+
+        # Set datetime constraints after lower bound, and with too little space left in window for obs duration
+        self.clear_time_constraints()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 13, 0, 0).isoformat()
+        self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                             datetime(2020, 1, 1, 12, 0, 0),
                                                                             datetime(2020, 1, 2, 12, 0, 0)))
 
+    def test_can_run_within_before_returns_true(self):
+
+        # Set datetime constraints after upper bounds, and with sufficient window for obs duration
+        self.clear_time_constraints()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 13, 0, 0).isoformat()
+        self.assertTrue(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                            datetime(2020, 1, 1, 12, 0, 0),
+                                                                            datetime(2020, 1, 2, 12, 0, 0)))
+
+        # Set datetime constraints after lower bounds, but with sufficient space left in window for obs duration
+        self.clear_time_constraints()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 15, 0, 0).isoformat()
+        self.assertTrue(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                            datetime(2020, 1, 1, 12, 0, 0),
+                                                                            datetime(2020, 1, 2, 12, 0, 0)))
+
+    # 'between' constraint
+
     def test_can_run_anywhere_between_returns_false(self):
         """
         Test 'between' constraint with start/stop datetime constraints 'outside' upper_bound or lower_bound
         """
         # Set datetime constraints start > lower_bound and stop > upper_bound
+        self.clear_time_constraints()
         self.add_time_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 2, 15, 0, 0))
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                          datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)))
+
         # Set datetime constraints start < lower_bound and stop < upper_bound
+        self.clear_time_constraints()
         self.add_time_between_constraint(datetime(2020, 1, 1, 8, 0, 0), datetime(2020, 1, 2, 8, 0, 0))
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                          datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)))
+
         # Set datetime constraints start > lower_bound and stop > upper_bound (1 second only)
+        self.clear_time_constraints()
         self.add_time_between_constraint(datetime(2020, 1, 1, 12, 0, 1), datetime(2020, 1, 2, 12, 0, 1))
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                          datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)))
 
+        # Set datetime constraints start > lower_bound and stop < upper_bound
+        self.clear_time_constraints()
+        self.add_time_between_constraint(datetime(2020, 1, 1, 18, 0, 0), datetime(2020, 1, 1, 19, 0, 0))
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                         datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)))
+
     def test_can_run_anywhere_between_returns_true(self):
         """
-        Test 'between' constraint with start/stop datetime constraints 'inside' upper_bound and lower_bound
+        Test 'between' constraint with start/stop datetime constraints 'outside' upper_bound and lower_bound
         """
-        # Set datetime constraints start > lower_bound and stop < upper_bound -duration
-        self.add_time_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 1, 15, 0, 0))
+        # Set datetime constraints start < lower_bound and stop > upper_bound
+        self.clear_time_constraints()
+        self.add_time_between_constraint(datetime(2020, 1, 1, 11, 0, 0), datetime(2020, 1, 2, 13, 0, 0))
         self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
-                                         datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 20, 0, 0)))
+                                         datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)))
 
-        # Set datetime constraints start = lower_bound and stop = upper_bound - duration
-        self.add_time_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 1, 15, 0, 0))
+        # Set datetime constraints start = lower_bound and stop = upper_bound
+        self.clear_time_constraints()
+        self.add_time_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))
         self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
-                                         datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 1, 17, 10, 0)))
+                                         datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)))
+
+    def test_can_run_within_between_returns_true(self):
+        """
+        Test 'between' constraint with start/stop datetime constraints (within, not anywhere within)
+        """
+        # Set datetime constraints start > lower_bound and stop > upper_bound, large window
+        self.clear_time_constraints()
+        self.add_time_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 2, 12, 0, 0))
+        self.assertTrue(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                         datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 20, 0, 0)))
+
+        # Set datetime constraints start = lower_bound and stop = upper_bound, window just large enough for obs
+        self.clear_time_constraints()
+        self.add_time_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 14, 0, 0))
+        self.assertTrue(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                         datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 14, 10, 0)))
+
+    def test_can_run_within_between_returns_false(self):
+        """
+        Test 'between' constraint with start/stop datetime constraints (within, not anywhere within)
+        """
+        # Set datetime constraints start < lower_bound and stop < upper_bound, too little overlap for obs
+        self.clear_time_constraints()
+        self.add_time_between_constraint(datetime(2020, 1, 1, 10, 0, 0), datetime(2020, 1, 1, 13, 0, 0))
+        self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                         datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 20, 0, 0)))
+
+        # Set datetime constraints start > lower_bound and stop < upper_bound, constraint window too small for obs
+        self.clear_time_constraints()
+        self.add_time_between_constraint(datetime(2020, 1, 1, 14, 0, 0), datetime(2020, 1, 1, 15, 0, 0))
+        self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                         datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 20, 10, 0)))
+
+    # 'not between' contraint
 
     def test_can_run_anywhere_not_between_returns_false(self):
         """
         Test 'not_between' constraint with start/stop datetime constraints 'inside' upper_bound or lower_bound
         """
         # Set datetime constraints start > lower_bound and stop > upper_bound
+        self.clear_time_constraints()
         self.add_time_not_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 2, 15, 0, 0))
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                              datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)))
 
         # Set datetime constraints start < lower_bound and stop > lower_bound and < upper_bound
+        self.clear_time_constraints()
         self.add_time_not_between_constraint(datetime(2020, 1, 1, 8, 0, 0), datetime(2020, 1, 2, 8, 0, 0))
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                              datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)))
 
         # Set datetime constraints start > lower_bound and stop < upper_bound
+        self.clear_time_constraints()
         self.add_time_not_between_constraint(datetime(2020, 1, 1, 16, 0, 0), datetime(2020, 1, 2, 8, 0, 0))
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                              datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)))
 
         # Set datetime constraints start < lower_bound and stop > upper_bound
+        self.clear_time_constraints()
         self.add_time_not_between_constraint(datetime(2020, 1, 1, 8, 0, 0), datetime(2020, 1, 2, 14, 0, 0))
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                             datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)))
@@ -950,23 +1152,78 @@ class TestTimeConstraints(TestCase):
         Test 'not_between' constraint with start/stop datetime constraints 'outside' upper_bound and lower_bound
         """
         # Set datetime constraints start < lower_bound and stop < lower_bound
+        self.clear_time_constraints()
         self.add_time_not_between_constraint(datetime(2020, 1, 1, 3, 0, 0), datetime(2020, 1, 1, 11, 0, 0))
         self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                              datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 16, 0, 0)))
 
         # Set datetime constraints start > upper_bound and stop > upper_bound
+        self.clear_time_constraints()
         self.add_time_not_between_constraint(datetime(2020, 1, 1, 16, 0, 0), datetime(2020, 1, 1, 20, 0, 0))
         self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                              datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 1, 15, 0, 0)))
 
+    # several simultaneous time ranges in 'at' / 'between' / 'not between' constraints
+
     def execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary(self):
         """
-        Just a simple wrapper to call 'can_run_anywhere_within_timewindow_with_time_constraints' function
+        Just a simple wrapper to call 'can_run_within_timewindow_with_time_constraints' function
         with a 24 hours boundary 2020-01-01 12:00 - 2020-01-02 12:00
         """
         return (tc1.can_run_within_timewindow_with_time_constraints(
                     self.scheduling_unit_blueprint, datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)))
 
+    def test_can_run_within_at_constraint(self):
+        """
+        Test "at" constraint with both boundary and 'inside' upper_bound and lower_bound
+        """
+        # no constraints defined so should be OK
+        self.clear_time_constraints()
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # Set datetime constraint before lower_bound
+        self.clear_time_constraints()
+        self.add_time_at_constraint(datetime(2020, 1, 1, 11, 0, 0))
+        self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                            datetime(2020, 1, 1, 12, 0, 0),
+                                                                            datetime(2020, 1, 1, 14, 0, 0)))
+
+        # Set datetime constraint at lower_bound, but duration exceeds upper_bound
+        self.clear_time_constraints()
+        self.add_time_at_constraint(datetime(2020, 1, 1, 12, 0, 0))
+        self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                            datetime(2020, 1, 1, 12, 0, 0),
+                                                                            datetime(2020, 1, 1, 14, 0, 0)))
+
+        # Set datetime constraint at upper_bound
+        self.clear_time_constraints()
+        self.add_time_at_constraint(datetime(2020, 1, 1, 14, 0, 0))
+        self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                             datetime(2020, 1, 1, 12, 0, 0),
+                                                                             datetime(2020, 1, 1, 14, 0, 0)))
+
+        # Set datetime constraint after upper_bound
+        self.clear_time_constraints()
+        self.add_time_at_constraint(datetime(2020, 1, 1, 15, 0, 0))
+        self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                            datetime(2020, 1, 1, 12, 0, 0),
+                                                                            datetime(2020, 1, 1, 14, 0, 0)))
+
+        # Set datetime constraint at lower_bound
+        self.clear_time_constraints()
+        self.add_time_at_constraint(datetime(2020, 1, 1, 12, 0, 0))
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # Set datetime constraint that fits the time window
+        self.clear_time_constraints()
+        self.add_time_at_constraint(datetime(2020, 1, 1, 18, 30, 0))
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # Set datetime constraint so that obs lasts till exactly upper_bound
+        self.clear_time_constraints()
+        self.add_time_at_constraint(datetime(2020, 1, 2, 9, 50, 0))
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
     def test_can_run_within_between_constraints(self):
         """
         Test multiple 'between' constraints within 24 boundary and check overall result of
@@ -976,39 +1233,41 @@ class TestTimeConstraints(TestCase):
         i.e. 12-14, 13-15, 14-16,..etc.., 9-11
         """
         # no constraints defined so should be OK
+        self.clear_time_constraints()
         self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
 
-        # Add constraints of 1hr, we still 'can_run'
+        # Add constraints of 1hr, we cannot run
         self.add_time_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 1, 14, 0, 0))
         self.add_time_between_constraint(datetime(2020, 1, 1, 16, 0, 0), datetime(2020, 1, 1, 17, 0, 0))
-        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+        self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
 
-        # Add constraints of 2hr, we still 'can_run'
+        # Add constraints of 2hr, but partially outside the bounds, we still cannot run
         self.add_time_between_constraint(datetime(2020, 1, 2, 11, 0, 0), datetime(2020, 1, 2, 13, 0, 0))
+        self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # Add constraints of 2hr, we can run again
+        self.add_time_between_constraint(datetime(2020, 1, 1, 17, 0, 0), datetime(2020, 1, 1, 19, 0, 0))
         self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
 
         # Add constraint of 24hr constraint, we still 'can_run'
         self.add_time_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))
         self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
 
-        # Add constraint of 2hr, to fill the 'last gap', we 'can run'
-        self.add_time_between_constraint(datetime(2020, 1, 2, 10, 0, 0), datetime(2020, 1, 2, 12, 0, 0))
-        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
-
         # Clear all between constraints
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["between"] = []
+        self.clear_time_constraints()
 
-        # Add constraints 'outside' the 24hr, now we 'can not run'
-        self.add_time_between_constraint(datetime(2020, 1, 2, 13, 0, 0), datetime(2020, 1, 2, 14, 0, 0))
-        self.add_time_between_constraint(datetime(2020, 1, 2, 16, 0, 0), datetime(2020, 1, 2, 17, 0, 0))
+        # Add constraints after the 24hr, now we 'can not run'
+        self.add_time_between_constraint(datetime(2020, 1, 2, 13, 0, 0), datetime(2020, 1, 2, 15, 0, 0))
+        self.add_time_between_constraint(datetime(2020, 1, 2, 16, 0, 0), datetime(2020, 1, 2, 20, 0, 0))
         self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
 
-        # Add constraint 'outside' the 24hr, we 'still can not run'
+        # Add constraint before the 24hr, we 'still can not run'
         self.add_time_between_constraint(datetime(2020, 1, 1, 9, 0, 0), datetime(2020, 1, 1, 12, 0, 0))
         self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
 
-        # add one 'inside' constraint, 1 hour within block of 2 hour so overall must be ok
-        self.add_time_between_constraint(datetime(2020, 1, 1, 13, 30, 0), datetime(2020, 1, 1, 14, 30, 0))
+        # add one 'inside' constraint of 3 hours, so overall must be ok again.
+        # Note that 2 hrs would only be sufficient if they match the moving window exactly (here: full hour)
+        self.add_time_between_constraint(datetime(2020, 1, 1, 14, 30, 0), datetime(2020, 1, 1, 17, 30, 0))
         self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
 
     def test_can_run_within_not_between_constraints(self):
@@ -1020,6 +1279,7 @@ class TestTimeConstraints(TestCase):
         i.e. 12-14, 13-15, 14-16,..etc.., 9-11
         """
         # no constraints defined so should be OK
+        self.clear_time_constraints()
         self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
 
         # Add constraints of 1hr, we still 'can_run'
@@ -1039,12 +1299,60 @@ class TestTimeConstraints(TestCase):
         self.add_time_not_between_constraint(datetime(2020, 1, 2, 10, 0, 0), datetime(2020, 1, 2, 12, 0, 0))
         self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
 
-        # Clear all not_between constraints
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["not_between"] = []
+        self.clear_time_constraints()
+
         # Add 4 hr constraints within 24 hours boundary, we can run
         self.add_time_not_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 16, 0, 0))
         self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
 
+    # combined time contraints tests
+
+    def test_can_run_anywhere_combined_time_constraints(self):
+        """
+        Test multiple time constraints in combination and make sure that they block the time window as expected,
+        even though each constraint individually would allow the observation to run.
+        """
+
+        # Set before and after constraint with sufficient gap to fit observation, and assert True
+        self.clear_time_constraints()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 12, 59, 59).isoformat()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 15, 0, 1).isoformat()
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # set before and after constraint with slightly smaller gap for observation, and assert False
+        self.clear_time_constraints()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 13, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 15, 0, 0).isoformat()
+        self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # set before and after constraint with large gap
+        # then and add additional between and not between constraints until window is blocked
+        # can run 13-8h
+        self.clear_time_constraints()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 13, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 8, 0, 0).isoformat()
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # can run 13h-20h
+        self.add_time_between_constraint(datetime(2020, 1, 1, 11, 0, 0), datetime(2020, 1, 1, 20, 0, 0))
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # can run 13h-17h
+        self.add_time_not_between_constraint(datetime(2020, 1, 1, 17, 0, 0), datetime(2020, 1, 2, 4, 0, 0))
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # can not run anymore
+        self.add_time_not_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 16, 0, 0))
+        self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # add another between window, can run 4h-8h
+        self.add_time_between_constraint(datetime(2020, 1, 1, 2, 0, 0), datetime(2020, 1, 2, 12, 0, 0))
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # move before constraint, can not run anymore
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 5, 0, 0).isoformat()
+        self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
 
 class TestReservedStations(unittest.TestCase):
     """
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/adapters/parset.py b/SAS/TMSS/backend/src/tmss/tmssapp/adapters/parset.py
index 00ed6e2a27944488a317e540fa46c972b8b0f13e..313aaf8090155c185fcc8ee7b62243dd52c8f74b 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/adapters/parset.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/adapters/parset.py
@@ -439,7 +439,7 @@ def _convert_to_parset_dict_for_pipelinecontrol_schema(subtask: models.Subtask)
 
     # DPPP steps
     dppp_steps = []
-    if "preflagger0" in spec:
+    if spec["preflagger0"]["enabled"]:
         dppp_steps.append('preflagger[0]')
         parset["Observation.ObservationControl.PythonControl.DPPP.preflagger[0].chan"] = "[%s]" % spec["preflagger0"]["channels"]
         parset["Observation.ObservationControl.PythonControl.DPPP.preflagger[0].abstime"] = "[]"
@@ -458,7 +458,7 @@ def _convert_to_parset_dict_for_pipelinecontrol_schema(subtask: models.Subtask)
         parset["Observation.ObservationControl.PythonControl.DPPP.preflagger[0].timeslot"] = "[]"
         parset["Observation.ObservationControl.PythonControl.DPPP.preflagger[0].type"] = "preflagger"
 
-    if 'preflagger1' in spec:
+    if spec["preflagger1"]["enabled"]:
         dppp_steps.append('preflagger[1]')
         parset["Observation.ObservationControl.PythonControl.DPPP.preflagger[1].corrtype"] = spec["preflagger1"]["corrtype"]
         parset["Observation.ObservationControl.PythonControl.DPPP.preflagger[1].abstime"] = "[]"
@@ -477,7 +477,7 @@ def _convert_to_parset_dict_for_pipelinecontrol_schema(subtask: models.Subtask)
         parset["Observation.ObservationControl.PythonControl.DPPP.preflagger[1].timeslot"] = "[]"
         parset["Observation.ObservationControl.PythonControl.DPPP.preflagger[1].type"] = "preflagger"
 
-    if 'aoflagger' in spec:
+    if spec["aoflagger"]["enabled"]:
         dppp_steps.append('aoflagger')
         parset["Observation.ObservationControl.PythonControl.DPPP.aoflagger.strategy"] = spec["aoflagger"]["strategy"]
         parset["Observation.ObservationControl.PythonControl.DPPP.aoflagger.autocorr"] = "F"
@@ -493,7 +493,7 @@ def _convert_to_parset_dict_for_pipelinecontrol_schema(subtask: models.Subtask)
         parset["Observation.ObservationControl.PythonControl.DPPP.aoflagger.timewindow"] = "0"
         parset["Observation.ObservationControl.PythonControl.DPPP.aoflagger.type"] = "aoflagger"
 
-    if "demixer" in spec:
+    if spec["demixer"]["enabled"]:
         dppp_steps.append('demixer')
         parset["Observation.ObservationControl.PythonControl.DPPP.demixer.baseline"] = spec["demixer"]["baselines"]
         parset["Observation.ObservationControl.PythonControl.DPPP.demixer.demixfreqstep"] = spec["demixer"]["demix_frequency_steps"]
@@ -514,6 +514,10 @@ def _convert_to_parset_dict_for_pipelinecontrol_schema(subtask: models.Subtask)
         parset["Observation.ObservationControl.PythonControl.DPPP.demixer.subtractsources"] = ""
         parset["Observation.ObservationControl.PythonControl.DPPP.demixer.targetsource"] = ""
         parset["Observation.ObservationControl.PythonControl.DPPP.demixer.type"] = "demixer"
+    else:
+        # ResourceEstimator wants these keys always
+        parset["Observation.ObservationControl.PythonControl.DPPP.demixer.freqstep"] = 1
+        parset["Observation.ObservationControl.PythonControl.DPPP.demixer.timestep"] = 1
 
     parset["Observation.ObservationControl.PythonControl.DPPP.steps"] = "[%s]" % ",".join(dppp_steps)
     parset["Observation.ObservationControl.PythonControl.DPPP.msout.storagemanager.name"] = spec["storagemanager"]
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/adapters/sip.py b/SAS/TMSS/backend/src/tmss/tmssapp/adapters/sip.py
index 50f95df8bd533083a2553df25b75c9c2480197e8..a48351c71b22a4b5a8335b81dbcba56eb7bb144a 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/adapters/sip.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/adapters/sip.py
@@ -2,6 +2,7 @@ from lofar.sas.tmss.tmss.exceptions import *
 from lofar.sas.tmss.tmss.tmssapp.models.scheduling import Dataproduct, SubtaskType, Subtask, SubtaskOutput, SIPidentifier, HashAlgorithm
 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
 
 import uuid
 import logging
@@ -182,13 +183,14 @@ def create_sip_representation_for_subtask(subtask: Subtask):
                 process_map=process_map)
 
         if subtask.specifications_template.name == "pipeline control":  #  todo: re-evaluate this because schema name might change
+            spec = add_defaults_to_json_object_for_schema(subtask.specifications_doc, subtask.specifications_template.schema)
             pipeline = siplib.AveragingPipeline(  # <-- this is what we need for UC1
                 pipeline_map,
                 numberofcorrelateddataproducts=get_number_of_dataproducts_of_type(subtask, Dataformat.Choices.MEASUREMENTSET.value),
-                frequencyintegrationstep=subtask.specifications_doc.get('demixer',{}).get('frequency_steps', 0),
-                timeintegrationstep=subtask.specifications_doc.get('demixer',{}).get('time_step', 0),
-                flagautocorrelations=subtask.task_blueprint.specifications_doc["flag"]["autocorrelations"],
-                demixing=True if 'demix' in subtask.task_blueprint.specifications_doc else False
+                frequencyintegrationstep=spec['demixer']['frequency_steps'] if spec['demixer']['enabled'] else 1,
+                timeintegrationstep=spec['demixer']['time_steps'] if spec['demixer']['enabled'] else 1,
+                flagautocorrelations=spec['preflagger1']['enabled'] and spec['preflagger1']['corrtype'] == 'auto',
+                demixing=spec['demixer']['enabled'] and (spec['demixer']['demix_always'] or spec['demixer']['demix_if_needed'])
             )
         # todo: distinguish and create other pipeline types. Probably most of these can be filled in over time as needed,
         #  but they are not required for UC1. Here are stubs to start from for the other types the LTA supports:
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0001_initial.py b/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0001_initial.py
index a9cddbddaa1da05b95912ba398541c7fd8d7001b..bdc69f9dca0dc9465fa1abcd5ca0033851ccd739 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0001_initial.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0001_initial.py
@@ -351,6 +351,15 @@ class Migration(migrations.Migration):
                 'abstract': False,
             },
         ),
+        migrations.CreateModel(
+            name='IOType',
+            fields=[
+                ('value', models.CharField(max_length=128, primary_key=True, serialize=False, unique=True)),
+            ],
+            options={
+                'abstract': False,
+            },
+        ),
         migrations.CreateModel(
             name='HashAlgorithm',
             fields=[
@@ -928,12 +937,12 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='taskrelationdraft',
             name='input_role',
-            field=models.ForeignKey(help_text='Input connector type (what kind of data can be taken as input).', on_delete=django.db.models.deletion.CASCADE, related_name='taskrelationdraft_input_roles', to='tmssapp.TaskConnectorType'),
+            field=models.ForeignKey(help_text='Input connector type (what kind of data is given to the consumer).', on_delete=django.db.models.deletion.CASCADE, related_name='taskrelationdraft_input_roles', to='tmssapp.TaskConnectorType'),
         ),
         migrations.AddField(
             model_name='taskrelationdraft',
             name='output_role',
-            field=models.ForeignKey(help_text='Output connector type (what kind of data can be created as output).', on_delete=django.db.models.deletion.CASCADE, related_name='taskrelationdraft_output_roles', to='tmssapp.TaskConnectorType'),
+            field=models.ForeignKey(help_text='Output connector type (what kind of data is taken from the producer).', on_delete=django.db.models.deletion.CASCADE, related_name='taskrelationdraft_output_roles', to='tmssapp.TaskConnectorType'),
         ),
         migrations.AddField(
             model_name='taskrelationdraft',
@@ -1012,18 +1021,18 @@ class Migration(migrations.Migration):
         ),
         migrations.AddField(
             model_name='taskconnectortype',
-            name='input_of',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='input_connector_types', to='tmssapp.TaskTemplate'),
+            name='iotype',
+            field=models.ForeignKey(help_text='Is this connector an input or output', on_delete=django.db.models.deletion.PROTECT, to='tmssapp.IOType'),
         ),
         migrations.AddField(
             model_name='taskconnectortype',
-            name='output_of',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='output_connector_types', to='tmssapp.TaskTemplate'),
+            name='role',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='tmssapp.Role'),
         ),
         migrations.AddField(
             model_name='taskconnectortype',
-            name='role',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='tmssapp.Role'),
+            name='task_template',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='output_connector_types', to='tmssapp.TaskTemplate'),
         ),
         migrations.AddField(
             model_name='taskblueprint',
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0002_populate.py b/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0002_populate.py
index 0fece500a4fdfb63d13d81b325dd60bc7c955b7b..92baffd4c15a8c025d234eeffed61ae9f443fabf 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0002_populate.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0002_populate.py
@@ -21,4 +21,4 @@ class Migration(migrations.Migration):
                    migrations.RunPython(populate_misc),
                    migrations.RunPython(populate_resources),
                    migrations.RunPython(populate_cycles),
-                   migrations.RunPython(populate_projects)]
+                   migrations.RunPython(populate_projects) ]
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/models/common.py b/SAS/TMSS/backend/src/tmss/tmssapp/models/common.py
index 9631cfc2fc3d8051ae1c586b673a8c4d3b553065..80a9fb61594cbe8996f45fe0b0b35a1c842fe319 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/models/common.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/models/common.py
@@ -14,6 +14,18 @@ from django.urls import reverse as reverse_url
 import json
 import jsonschema
 
+class RefreshFromDbInvalidatesCachedPropertiesMixin():
+    """Helper Mixin class which invalidates all 'cached_property' attributes on a model upon refreshing from the db"""
+    def refresh_from_db(self, *args, **kwargs):
+        self.invalidate_cached_properties()
+        return super().refresh_from_db(*args, **kwargs)
+
+    def invalidate_cached_properties(self):
+        from django.utils.functional import cached_property
+        for key, value in self.__class__.__dict__.items():
+            if isinstance(value, cached_property):
+                self.__dict__.pop(key, None)
+
 # abstract models
 
 class BasicCommon(Model):
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py b/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py
index 5173917b236f9ac4752319a568a2a14d0d317002..b661e36bb885187d2f512047f9441aa68e948b70 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py
@@ -10,7 +10,7 @@ from django.contrib.postgres.fields import JSONField
 from enum import Enum
 from django.db.models.expressions import RawSQL
 from django.db.models.deletion import ProtectedError
-from .common import AbstractChoice, BasicCommon, Template, NamedCommon, annotate_validate_add_defaults_to_doc_using_template, NamedCommonPK
+from .common import AbstractChoice, BasicCommon, Template, NamedCommon, annotate_validate_add_defaults_to_doc_using_template, NamedCommonPK, RefreshFromDbInvalidatesCachedPropertiesMixin
 from lofar.common.json_utils import validate_json_against_schema, validate_json_against_its_schema, add_defaults_to_json_object_for_schema
 from lofar.sas.tmss.tmss.exceptions import *
 from django.core.exceptions import ValidationError
@@ -23,7 +23,7 @@ from django.utils.functional import cached_property
 # Mixins
 #
 
-class ProjectPropertyMixin:
+class ProjectPropertyMixin(RefreshFromDbInvalidatesCachedPropertiesMixin):
     @cached_property
     def project(self): # -> Project:
         '''return the related project of this task
@@ -52,8 +52,16 @@ class Role(AbstractChoice):
         INSPECTION_PLOTS = "inspection plots"
         CALIBRATOR = "calibrator"
         TARGET = "target"
+        ANY = "any"
+
+
+class IOType(AbstractChoice):
+    """Defines the model and predefined list of possible IOType's for TaskConnectorType.
+    The items in the Choises class below are automagically populated into the database via a data migration."""
+    class Choices(Enum):
         INPUT = "input"
         OUTPUT = "output"
+        # maybe we can add an IN_PLACE="in_place" option in the future, but for now it's not needed.
 
 
 class Datatype(AbstractChoice):
@@ -156,11 +164,15 @@ class Setting(BasicCommon):
 
 
 class TaskConnectorType(BasicCommon):
+    ''' Describes the data type & format combinations a Task can accept or produce. The "role" is used to distinguish
+        inputs (or outputs) that have the same data type & format, but are used in different ways by the task. For
+        example, a calibration pipeline accepts measurement sets only, but distinghuishes between CALIBRATOR and
+        TARGET roles.'''
     role = ForeignKey('Role', null=False, on_delete=PROTECT)
     datatype = ForeignKey('Datatype', null=False, on_delete=PROTECT)
     dataformats = ManyToManyField('Dataformat', blank=True)
-    output_of = ForeignKey("TaskTemplate", related_name='output_connector_types', on_delete=CASCADE)
-    input_of = ForeignKey("TaskTemplate", related_name='input_connector_types', on_delete=CASCADE)
+    task_template = ForeignKey("TaskTemplate", related_name='output_connector_types', null=False, on_delete=CASCADE)
+    iotype = ForeignKey('IOType', null=False, on_delete=PROTECT, help_text="Is this connector an input or output")
 
 
 #
@@ -268,7 +280,7 @@ class DefaultReservationTemplate(BasicCommon):
 # Instance Objects
 #
 
-class Cycle(NamedCommonPK):
+class Cycle(RefreshFromDbInvalidatesCachedPropertiesMixin, NamedCommonPK):
     start = DateTimeField(help_text='Moment at which the cycle starts, that is, when its projects can run.')
     stop = DateTimeField(help_text='Moment at which the cycle officially ends.')
 
@@ -295,7 +307,7 @@ class CycleQuota(Model):
     resource_type = ForeignKey('ResourceType', on_delete=PROTECT, help_text='Resource type.')
 
 
-class Project(NamedCommonPK):
+class Project(RefreshFromDbInvalidatesCachedPropertiesMixin, NamedCommonPK):
     # todo: cycles should be protected since we have to manually decide to clean up projects with a cycle or keep them without cycle, however, ManyToManyField does not allow for that
     cycles = ManyToManyField('Cycle', related_name='projects', blank=True, help_text='Cycles to which this project belongs (NULLable).')
     priority_rank = FloatField(null=False, help_text='Priority of this project w.r.t. other projects. Projects can interrupt observations of lower-priority projects.') # todo: add if needed: validators=[MinValueValidator(0.0), MaxValueValidator(1.0)]
@@ -327,7 +339,7 @@ class ProjectQuota(Model):
     resource_type = ForeignKey('ResourceType', on_delete=PROTECT, help_text='Resource type.')  # protected to avoid accidents
 
 
-class ProjectQuotaArchiveLocation(Model):
+class ProjectQuotaArchiveLocation(RefreshFromDbInvalidatesCachedPropertiesMixin, Model):
     project_quota = ForeignKey('ProjectQuota', null=False, related_name="project_quota_archive_location", on_delete=PROTECT, help_text='The ProjectQuota for this archive location')
     archive_location = ForeignKey('Filesystem', null=False, on_delete=PROTECT, help_text='Location of an archive LTA cluster.')
 
@@ -364,7 +376,7 @@ class SchedulingSet(NamedCommon):
         super().save(force_insert, force_update, using, update_fields)
 
 
-class SchedulingUnitDraft(NamedCommon):
+class SchedulingUnitDraft(RefreshFromDbInvalidatesCachedPropertiesMixin, NamedCommon):
     requirements_doc = JSONField(help_text='Scheduling and/or quality requirements for this run.')
     copies = ForeignKey('SchedulingUnitDraft', related_name="copied_from", on_delete=SET_NULL, null=True, help_text='Source reference, if we are a copy (NULLable).')
     copy_reason = ForeignKey('CopyReason', null=True, on_delete=PROTECT, help_text='Reason why source was copied (NULLable).')
@@ -428,7 +440,7 @@ class SchedulingUnitDraft(NamedCommon):
         return self.scheduling_set.project
 
 
-class SchedulingUnitBlueprint(NamedCommon):
+class SchedulingUnitBlueprint(RefreshFromDbInvalidatesCachedPropertiesMixin, NamedCommon):
     class Status(Enum):
         DEFINED = "defined"
         FINISHED = "finished"
@@ -827,7 +839,7 @@ class TaskDraft(NamedCommon, ProjectPropertyMixin):
     #         return None
 
 
-class TaskBlueprint(NamedCommon):
+class TaskBlueprint(RefreshFromDbInvalidatesCachedPropertiesMixin, NamedCommon):
 
     specifications_doc = JSONField(help_text='Schedulings for this task (IMMUTABLE).')
     do_cancel = BooleanField(help_text='Cancel this task.')
@@ -985,13 +997,20 @@ class TaskRelationDraft(BasicCommon):
     # caveat: it might look like consumer has an incorrect related_name='produced_by'. But it really is correct, denends on the way you look at it
     consumer = ForeignKey('TaskDraft', related_name='produced_by', on_delete=CASCADE, help_text='Task Draft that has the input connector.')
 
-    input_role = ForeignKey('TaskConnectorType', related_name='taskrelationdraft_input_roles', on_delete=CASCADE, help_text='Input connector type (what kind of data can be taken as input).')
-    output_role = ForeignKey('TaskConnectorType', related_name='taskrelationdraft_output_roles', on_delete=CASCADE, help_text='Output connector type (what kind of data can be created as output).')
+    # this relation descibes a transfer of data from the output_role of the producer to the input_role of the consumer
+    input_role = ForeignKey('TaskConnectorType', related_name='taskrelationdraft_input_roles', on_delete=CASCADE, help_text='Input connector type (what kind of data is given to the consumer).')
+    output_role = ForeignKey('TaskConnectorType', related_name='taskrelationdraft_output_roles', on_delete=CASCADE, help_text='Output connector type (what kind of data is taken from the producer).')
 
     class Meta:
         # ensure there are no duplicate relations between tasks with the same in/out roles.
         constraints = [UniqueConstraint(fields=['producer', 'consumer', 'input_role', 'output_role'], name='TaskRelationDraft_unique_relation')]
 
+        # ensure that the roles are compatible, that is, the output we take is suitable for the input we provide to:
+        # input_role.dataformat == output_role.dataformat
+        # input_role.datatype == outputrole.datatype
+        # input_role.output = False
+        # output_role.output = True
+
     def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
         annotate_validate_add_defaults_to_doc_using_template(self, 'selection_doc', 'selection_template')
         super().save(force_insert, force_update, using, update_fields)
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/populate.py b/SAS/TMSS/backend/src/tmss/tmssapp/populate.py
index a53992b096237eb18d0033db76221516a02f51f3..280701a72043b5892b926a1eecb5eefb1455f309 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/populate.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/populate.py
@@ -40,7 +40,7 @@ def populate_choices(apps, schema_editor):
     each 'choice'type in Role, Datatype, Dataformat, CopyReason
     :return: None
     '''
-    choice_classes = [Role, Datatype, Dataformat, CopyReason,
+    choice_classes = [Role, IOType, Datatype, Dataformat, CopyReason,
                       SubtaskState, SubtaskType, StationType, HashAlgorithm, SchedulingRelationPlacement,
                       Flag, ProjectCategory, PeriodCategory, Quantity, TaskType, ProjectRole]
 
@@ -349,16 +349,45 @@ def populate_misc(apps, schema_editor):
 
 def populate_connectors():
     # the TaskConnectorType's define how the Task[Draft/Blueprint] *can* be connected.
-    # TODO Need overview which we do actually need
-    TaskConnectorType.objects.create(role=Role.objects.get(value=Role.Choices.INPUT.value),
+
+    # NOTE: This is an explicit list of each possible link between tasks. This model suffices
+    # until the number of connectors throw too large. By then, we could consider introducing
+    # wild cards, like output_of=NULL meaning "any".
+    logger.info("POPULATING CONNECTORS")
+
+    # calibrator observation
+    TaskConnectorType.objects.create(role=Role.objects.get(value=Role.Choices.CORRELATOR.value),
                                  datatype=Datatype.objects.get(value=Datatype.Choices.VISIBILITIES.value),
-                                 output_of=TaskTemplate.objects.get(name='calibrator observation'),
-                                 input_of=TaskTemplate.objects.get(name='preprocessing pipeline'))
+                                 task_template=TaskTemplate.objects.get(name='calibrator observation'),
+                                 iotype=IOType.objects.get(value=IOType.Choices.OUTPUT.value))
 
+    # target observation
     TaskConnectorType.objects.create(role=Role.objects.get(value=Role.Choices.CORRELATOR.value),
                                  datatype=Datatype.objects.get(value=Datatype.Choices.VISIBILITIES.value),
-                                 output_of=TaskTemplate.objects.get(name='calibrator observation'),
-                                 input_of=TaskTemplate.objects.get(name='preprocessing pipeline'))
+                                 task_template=TaskTemplate.objects.get(name='target observation'),
+                                 iotype=IOType.objects.get(value=IOType.Choices.OUTPUT.value))
+
+    # preprocessing pipeline
+    TaskConnectorType.objects.create(role=Role.objects.get(value=Role.Choices.ANY.value),
+                                 datatype=Datatype.objects.get(value=Datatype.Choices.VISIBILITIES.value),
+                                 task_template=TaskTemplate.objects.get(name='preprocessing pipeline'),
+                                 iotype=IOType.objects.get(value=IOType.Choices.INPUT.value))
+
+    TaskConnectorType.objects.create(role=Role.objects.get(value=Role.Choices.ANY.value),
+                                 datatype=Datatype.objects.get(value=Datatype.Choices.VISIBILITIES.value),
+                                 task_template=TaskTemplate.objects.get(name='preprocessing pipeline'),
+                                 iotype=IOType.objects.get(value=IOType.Choices.OUTPUT.value))
+
+    # ingest
+    TaskConnectorType.objects.create(role=Role.objects.get(value=Role.Choices.ANY.value),
+                                 datatype=Datatype.objects.get(value=Datatype.Choices.VISIBILITIES.value),
+                                 task_template=TaskTemplate.objects.get(name='ingest'),
+                                 iotype=IOType.objects.get(value=IOType.Choices.INPUT.value))
+
+    TaskConnectorType.objects.create(role=Role.objects.get(value=Role.Choices.ANY.value),
+                                 datatype=Datatype.objects.get(value=Datatype.Choices.TIME_SERIES.value),
+                                 task_template=TaskTemplate.objects.get(name='ingest'),
+                                 iotype=IOType.objects.get(value=IOType.Choices.INPUT.value))
 
 
 def populate_permissions():
@@ -573,23 +602,23 @@ def assign_system_permissions():
 
 def populate_system_test_users():
     # TODO: Set proper credentials (passwords at least).
-    to_observer_user = User.objects.create(username='to_observer', password='to_observer')
+    to_observer_user, _ = User.objects.get_or_create(username='to_observer', password='to_observer')
     to_observer_user.groups.add(Group.objects.get(name='TO observer'))
-    sdco_support_user = User.objects.create(username='sdco_support', password='sdco_support')
+    sdco_support_user, _ = User.objects.get_or_create(username='sdco_support', password='sdco_support')
     sdco_support_user.groups.add(Group.objects.get(name='SDCO support'))
-    tmss_maintainer_user = User.objects.create(username='tmss_maintainer', password='tmss_maintainer')
+    tmss_maintainer_user, _ = User.objects.get_or_create(username='tmss_maintainer', password='tmss_maintainer')
     tmss_maintainer_user.groups.add(Group.objects.get(name='TMSS Maintainer'))
-    tmss_admin_user = User.objects.create(username='tmss_admin', password='tmss_admin')
+    tmss_admin_user, _ = User.objects.get_or_create(username='tmss_admin', password='tmss_admin')
     tmss_admin_user.groups.add(Group.objects.get(name='TMSS Admin'))
-    to_maintenance_user = User.objects.create(username='to_maintenance', password='to_maintenance')
+    to_maintenance_user, _ = User.objects.get_or_create(username='to_maintenance', password='to_maintenance')
     to_maintenance_user.groups.add(Group.objects.get(name='TO maintenance'))
-    to_user = User.objects.create(username='to_user', password='to_user')
+    to_user, _ = User.objects.get_or_create(username='to_user', password='to_user')
     to_user.groups.add(Group.objects.get(name='TO user'))
-    scientist_user = User.objects.create(username='scientist', password='scientist')
+    scientist_user, _ = User.objects.get_or_create(username='scientist', password='scientist')
     scientist_user.groups.add(Group.objects.get(name='Scientist'))
-    e_scientist_user = User.objects.create(username='e_scientist', password='e_scientist')
+    e_scientist_user, _ = User.objects.get_or_create(username='e_scientist', password='e_scientist')
     e_scientist_user.groups.add(Group.objects.get(name='Scientist (Expert)'))
-    guest_user = User.objects.create(username='guest', password='guest')
+    guest_user, _ = User.objects.get_or_create(username='guest', password='guest')
     guest_user.groups.add(Group.objects.get(name='Guest'))
-    lta_user = User.objects.create(username='lta_user', password='lta_user')
+    lta_user, _ = User.objects.get_or_create(username='lta_user', password='lta_user')
     lta_user.groups.add(Group.objects.get(name='LTA User'))
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/schemas/UC1-scheduling-unit-observation-strategy.json b/SAS/TMSS/backend/src/tmss/tmssapp/schemas/UC1-scheduling-unit-observation-strategy.json
index 07081c0e3098153f07f55d8078608ece8776bec7..33a51e3c0f967a083a8cd8e212f68eddfed5f3bb 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/schemas/UC1-scheduling-unit-observation-strategy.json
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/schemas/UC1-scheduling-unit-observation-strategy.json
@@ -20,7 +20,7 @@
       "tags": [],
       "specifications_doc": {
         "flag": {
-          "rfi_strategy": "auto",
+          "rfi_strategy": "HBAdefault",
           "outerchannels": true,
           "autocorrelations": true
         },
@@ -115,7 +115,7 @@
       "tags": [],
       "specifications_doc": {
         "flag": {
-          "rfi_strategy": "auto",
+          "rfi_strategy": "HBAdefault",
           "outerchannels": true,
           "autocorrelations": true
         },
@@ -138,7 +138,7 @@
       "tags": [],
       "specifications_doc": {
         "flag": {
-          "rfi_strategy": "auto",
+          "rfi_strategy": "HBAdefault",
           "outerchannels": true,
           "autocorrelations": true
         },
@@ -176,7 +176,7 @@
       "tags": [],
       "specifications_doc": {
         "flag": {
-          "rfi_strategy": "auto",
+          "rfi_strategy": "HBAdefault",
           "outerchannels": true,
           "autocorrelations": true
         },
@@ -207,7 +207,7 @@
       "consumer": "Pipeline 1",
       "tags": [],
       "input": {
-        "role": "input",
+        "role": "any",
         "datatype": "visibilities"
       },
       "output": {
@@ -223,7 +223,7 @@
       "consumer": "Pipeline 2",
       "tags": [],
       "input": {
-        "role": "input",
+        "role": "any",
         "datatype": "visibilities"
       },
       "output": {
@@ -239,7 +239,7 @@
       "consumer": "Pipeline target1",
       "tags": [],
       "input": {
-        "role": "input",
+        "role": "any",
         "datatype": "visibilities"
       },
       "output": {
@@ -259,7 +259,7 @@
       "consumer": "Pipeline target2",
       "tags": [],
       "input": {
-        "role": "input",
+        "role": "any",
         "datatype": "visibilities"
       },
       "output": {
@@ -279,11 +279,11 @@
       "consumer": "Ingest",
       "tags": [],
       "input": {
-        "role": "input",
+        "role": "any",
         "datatype": "visibilities"
       },
       "output": {
-        "role": "correlator",
+        "role": "any",
         "datatype": "visibilities"
       },
       "dataformat": "MeasurementSet",
@@ -295,11 +295,11 @@
       "consumer": "Ingest",
       "tags": [],
       "input": {
-        "role": "input",
+        "role": "any",
         "datatype": "visibilities"
       },
       "output": {
-        "role": "correlator",
+        "role": "any",
         "datatype": "visibilities"
       },
       "dataformat": "MeasurementSet",
@@ -311,11 +311,11 @@
       "consumer": "Ingest",
       "tags": [],
       "input": {
-        "role": "input",
+        "role": "any",
         "datatype": "visibilities"
       },
       "output": {
-        "role": "correlator",
+        "role": "any",
         "datatype": "visibilities"
       },
       "dataformat": "MeasurementSet",
@@ -327,11 +327,11 @@
       "consumer": "Ingest",
       "tags": [],
       "input": {
-        "role": "input",
+        "role": "any",
         "datatype": "visibilities"
       },
       "output": {
-        "role": "correlator",
+        "role": "any",
         "datatype": "visibilities"
       },
       "dataformat": "MeasurementSet",
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/schemas/short-observation-pipeline-ingest-scheduling-unit-observation-strategy.json b/SAS/TMSS/backend/src/tmss/tmssapp/schemas/short-observation-pipeline-ingest-scheduling-unit-observation-strategy.json
index ac3277566c7e385713036301a3c2a6af7bd3c911..bd7eea6fc5ab98a051c05833e09c7baec4604a42 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/schemas/short-observation-pipeline-ingest-scheduling-unit-observation-strategy.json
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/schemas/short-observation-pipeline-ingest-scheduling-unit-observation-strategy.json
@@ -52,7 +52,7 @@
       "tags": [],
       "specifications_doc": {
         "flag": {
-          "rfi_strategy": "auto",
+          "rfi_strategy": "HBAdefault",
           "outerchannels": true,
           "autocorrelations": true
         },
@@ -83,7 +83,7 @@
       "consumer": "Pipeline",
       "tags": [],
       "input": {
-        "role": "input",
+        "role": "any",
         "datatype": "visibilities"
       },
       "output": {
@@ -99,7 +99,7 @@
       "consumer": "Ingest",
       "tags": [],
       "input": {
-        "role": "input",
+        "role": "any",
         "datatype": "visibilities"
       },
       "output": {
@@ -133,4 +133,4 @@
       "name": "Tile Beam"
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/schemas/subtask_template-pipeline-1.json b/SAS/TMSS/backend/src/tmss/tmssapp/schemas/subtask_template-pipeline-1.json
index 8307de613566df0b7a19d2417a24b740d3f41e7a..e52ab545b6fb1fc8224b83a9144f880dbd0fed1f 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/schemas/subtask_template-pipeline-1.json
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/schemas/subtask_template-pipeline-1.json
@@ -12,6 +12,11 @@
       "type": "object",
       "additionalProperties": false,
       "properties": {
+        "enabled": {
+          "type": "boolean",
+          "title": "Enabled",
+          "default": false
+        },
         "channels": {
           "title": "Channels",
           "type": "string",
@@ -19,7 +24,7 @@
         }
       },
       "required": [
-        "channels"
+        "enabled"
       ],
       "default": {}
     },
@@ -29,6 +34,11 @@
       "type": "object",
       "additionalProperties": false,
       "properties": {
+        "enabled": {
+          "type": "boolean",
+          "title": "Enabled",
+          "default": false
+        },
         "corrtype": {
           "title": "Correlations",
           "type": "string",
@@ -41,7 +51,7 @@
         }
       },
       "required": [
-        "corrtype"
+        "enabled"
       ],
       "default": {}
     },
@@ -51,6 +61,11 @@
       "type": "object",
       "additionalProperties": false,
       "properties": {
+        "enabled": {
+          "type": "boolean",
+          "title": "Enabled",
+          "default": false
+        },
         "strategy": {
           "title": "Strategy",
           "type": "string",
@@ -62,7 +77,7 @@
         }
       },
       "required": [
-        "strategy"
+        "enabled"
       ],
       "default": {}
     },
@@ -72,6 +87,11 @@
       "type": "object",
       "additionalProperties": false,
       "properties": {
+        "enabled": {
+          "type": "boolean",
+          "title": "Enabled",
+          "default": false
+        },
         "baselines": {
           "title": "Baselines",
           "type": "string",
@@ -142,14 +162,7 @@
         }
       },
       "required": [
-        "baselines",
-        "frequency_steps",
-        "time_steps",
-        "demix_frequency_steps",
-        "demix_time_steps",
-        "ignore_target",
-        "demix_always",
-        "demix_if_needed"
+        "enabled"
       ],
       "default": {}
     },
@@ -164,6 +177,5 @@
     }
   },
   "required": [
-    "storagemanager"
   ]
 }
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/schemas/task_template-preprocessing_pipeline-1.json b/SAS/TMSS/backend/src/tmss/tmssapp/schemas/task_template-preprocessing_pipeline-1.json
index 74278f49310705212c20f65d8afe9aa61fb6ed97..0c6e37c3eb7f976d4836e5354ee565726497499e 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/schemas/task_template-preprocessing_pipeline-1.json
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/schemas/task_template-preprocessing_pipeline-1.json
@@ -24,10 +24,9 @@
         "rfi_strategy": {
           "type": "string",
           "title": "RFI flagging strategy",
-          "default": "auto",
+          "default": "HBAdefault",
           "enum": [
             "none",
-            "auto",
             "HBAdefault",
             "LBAdefault"
           ]
@@ -122,16 +121,7 @@
         }
       },
       "required": [
-        "frequency_steps",
-        "time_steps",
-        "ignore_target",
-        "sources"
       ],
-      "options": {
-        "dependencies": {
-          "demix": true
-        }
-      },
       "default": {}
     },
     "storagemanager": {
@@ -139,12 +129,12 @@
       "title": "Storage Manager",
       "default": "dysco",
       "enum": [
-        "basic",
+        "standard",
         "dysco"
       ]
     }
   },
   "required": [
-    "storagemanager"
+    "average"
   ]
-}
\ No newline at end of file
+}
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/serializers/specification.py b/SAS/TMSS/backend/src/tmss/tmssapp/serializers/specification.py
index 47086104958108a4cc364a1c07c84c200d909d64..8e21947208819f013ba1c7d23bda3586cd774f91 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/serializers/specification.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/serializers/specification.py
@@ -102,6 +102,11 @@ class RoleSerializer(serializers.ModelSerializer):
         model = models.Role
         fields = '__all__'
 
+class IOTypeSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = models.IOType
+        fields = '__all__'
+
 class SchedulingRelationPlacementSerializer(serializers.ModelSerializer):
     class Meta:
         model = models.SchedulingRelationPlacement
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/subtasks.py b/SAS/TMSS/backend/src/tmss/tmssapp/subtasks.py
index 856c523be56c5a471099ab484f6eb04412b678a8..5c1513c829161770f6a6a8101976cbb03d0f5537 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/subtasks.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/subtasks.py
@@ -598,7 +598,8 @@ def create_preprocessing_subtask_from_task_blueprint(task_blueprint: TaskBluepri
     # step 1: create subtask in defining state, with filled-in subtask_template
     subtask_template = SubtaskTemplate.objects.get(name='pipeline control')
     default_subtask_specs = get_default_json_object_for_schema(subtask_template.schema)
-    subtask_specs = _generate_subtask_specs_from_preprocessing_task_specs(task_blueprint.specifications_doc, default_subtask_specs)
+    task_specs_with_defaults = add_defaults_to_json_object_for_schema(task_blueprint.specifications_doc, task_blueprint.specifications_template.schema)
+    subtask_specs = _generate_subtask_specs_from_preprocessing_task_specs(task_specs_with_defaults, default_subtask_specs)
     cluster_name = task_blueprint.specifications_doc.get("storage_cluster", "CEP4")
     subtask_data = { "start_time": None,
                      "stop_time": None,
@@ -1524,63 +1525,44 @@ def schedule_independent_subtasks_in_task_blueprint(task_blueprint: TaskBlueprin
 
 
 def _generate_subtask_specs_from_preprocessing_task_specs(preprocessing_task_specs, default_subtask_specs):
-    # preprocessing task default spec: {
-    #   "storagemanager": "dysco",
-    #   "flag": {"outerchannels": true, "autocorrelations": true, "rfi_strategy": "auto"},
-    #   "demix": {"frequency_steps": 64, "time_steps": 10, "ignore_target": false, "sources": {}},
-    #   "average": {"frequency_steps": 4, "time_steps": 1}}
-    # pipelinecontrol subtask default spec: {
-    #   "storagemanager": "dysco",
-    #   "demixer": {"baselines": "CS*,RS*&", "frequency_steps": 4, "time_steps": 1, "demix_frequency_steps": 4,
-    #               "demix_time_steps": 1, "ignore_target": false, "demix_always": [], "demix_if_needed": []},
-    #   "aoflagger": {"strategy": "HBAdefault"},
-    #    "preflagger0": {"channels": "0..nchan/32-1,31*nchan/32..nchan-1"},
-    #    "preflagger1": {"corrtype": "auto"}}
-
     # todo: check that this is actually how these need to be translated
     # todo: especially check when defaults are NOT supposed to be set because the task implies to not include them
 
-    # todo: translate task "sources": {} - I guess this is demix_always/demix_if_needed?
-    # todo: set subtask demixer properties "baselines": "CS*,RS*&", "demix_always": [], "demix_if_needed": []
-
-    subtask_specs = {}
-    subtask_specs['storagemanager'] = preprocessing_task_specs.get('storagemanager',
-                                                                   default_subtask_specs.get('storagemanager'))
-
-    # todo: we depend on valid json here with knowledge about required properties. To generalize, we need to expect things to not be there.
-    if 'demix' or 'average' in preprocessing_task_specs:
-        # todo: should we exclude defaults in subtask.demixer if only one of these is defined on the task?
-        subtask_specs['demixer'] = default_subtask_specs['demixer']
-        if 'demix' in preprocessing_task_specs:
-            subtask_specs['demixer'].update({
-                "demix_frequency_steps": preprocessing_task_specs['demix']['frequency_steps'],
-                "demix_time_steps": preprocessing_task_specs['demix']['time_steps'],
-                "ignore_target": preprocessing_task_specs['demix']['ignore_target']
-            }),
-        if 'average' in preprocessing_task_specs:
-            subtask_specs['demixer'].update({
-                "demix_frequency_steps": preprocessing_task_specs['demix']['frequency_steps'],
-                "frequency_steps": preprocessing_task_specs['average']['frequency_steps'],
-                "demix_time_steps": preprocessing_task_specs['demix']['time_steps'],
-                "time_steps": preprocessing_task_specs['average']['time_steps'],
-                "ignore_target": preprocessing_task_specs['demix']['ignore_target']
-            }),
-    if 'flag' in preprocessing_task_specs:
-        if preprocessing_task_specs["flag"]["rfi_strategy"] != 'none':
-            subtask_specs.update({"aoflagger": {"strategy": preprocessing_task_specs["flag"]["rfi_strategy"]}})
-
-            if preprocessing_task_specs["flag"]["rfi_strategy"] == 'auto':
-                # todo: handle 'auto' properly: we need to determine input dataproduct type and set LBA or HBA accordingly
-                #   either here or allow 'auto' in subtask json and translate it when we connect obs to pipe subtask
-                default_strategy = default_subtask_specs['aoflagger']['strategy']
-                subtask_specs.update({"aoflagger": {"strategy": default_strategy}})
-                logger.warning('Translating aoflagger "auto" strategy to "%s" without knowing whether that makes sense!' % default_strategy)
-
-        if preprocessing_task_specs["flag"]["outerchannels"]:
-            subtask_specs.update({"preflagger0": {"channels": "0..nchan/32-1,31*nchan/32..nchan-1"}})
-
-        if preprocessing_task_specs["flag"]["autocorrelations"]:
-            subtask_specs.update({"preflagger1": {"corrtype": "auto"}})
+    # todo: set subtask demixer properties "baselines": "CS*,RS*&"
+
+    subtask_specs = default_subtask_specs
+    subtask_specs['storagemanager'] = preprocessing_task_specs['storagemanager']
+
+    # averaging (performed by the demixer)
+    subtask_specs["demixer"]["enabled"]         = True
+    subtask_specs['demixer']["frequency_steps"] = preprocessing_task_specs['average']['frequency_steps']
+    subtask_specs['demixer']["time_steps"]      = preprocessing_task_specs['average']['time_steps']
+
+    # demixing
+    subtask_specs['demixer']["demix_frequency_steps"] = preprocessing_task_specs['demix']['frequency_steps']
+    subtask_specs['demixer']["demix_time_steps"]      = preprocessing_task_specs['demix']['time_steps']
+    subtask_specs['demixer']["ignore_target"]         = preprocessing_task_specs['demix']['ignore_target']
+    subtask_specs['demixer']["demix_always"]          = [source for source,strategy in preprocessing_task_specs['demix']['sources'].items() if strategy == "yes"]
+    subtask_specs['demixer']["demix_if_needed"]       = [source for source,strategy in preprocessing_task_specs['demix']['sources'].items() if strategy == "auto"]
+
+    # flagging
+    if preprocessing_task_specs["flag"]["rfi_strategy"] != 'none':
+        subtask_specs["aoflagger"]["enabled"] = True
+        subtask_specs["aoflagger"]["strategy"] = preprocessing_task_specs["flag"]["rfi_strategy"]
+    else:
+        subtask_specs["aoflagger"]["enabled"] = False
+
+    if preprocessing_task_specs["flag"]["outerchannels"]:
+        subtask_specs["preflagger0"]["enabled"] = True
+        subtask_specs["preflagger0"]["channels"] = "0..nchan/32-1,31*nchan/32..nchan-1"
+    else:
+        subtask_specs["preflagger0"]["enabled"] = False
+
+    if preprocessing_task_specs["flag"]["autocorrelations"]:
+        subtask_specs["preflagger1"]["enabled"] = True
+        subtask_specs["preflagger1"]["corrtype"] = "auto"
+    else:
+        subtask_specs["preflagger1"]["enabled"] = False
 
     return subtask_specs
 
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/tasks.py b/SAS/TMSS/backend/src/tmss/tmssapp/tasks.py
index 617ecfed46f6f83fa1b02623081932c8462e6bae..e6d9c06ebe4e38f60a459788c6d16f41569b237c 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/tasks.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/tasks.py
@@ -179,8 +179,8 @@ def create_task_drafts_from_scheduling_unit_draft(scheduling_unit_draft: models.
         producer_task_draft = scheduling_unit_draft.task_drafts.get(name=task_relation_definition["producer"])
         consumer_task_draft = scheduling_unit_draft.task_drafts.get(name=task_relation_definition["consumer"])
         dataformat = models.Dataformat.objects.get(value=task_relation_definition["dataformat"])
-        input_role = models.TaskConnectorType.objects.get(role=task_relation_definition["input"]["role"], datatype=task_relation_definition["input"]["datatype"])
-        output_role = models.TaskConnectorType.objects.get(role=task_relation_definition["output"]["role"], datatype=task_relation_definition["output"]["datatype"])
+        input_role = models.TaskConnectorType.objects.get(task_template=consumer_task_draft.specifications_template, role=task_relation_definition["input"]["role"], datatype=task_relation_definition["input"]["datatype"], iotype=models.IOType.objects.get(value=models.IOType.Choices.INPUT.value))
+        output_role = models.TaskConnectorType.objects.get(task_template=producer_task_draft.specifications_template, role=task_relation_definition["output"]["role"], datatype=task_relation_definition["output"]["datatype"], iotype=models.IOType.objects.get(value=models.IOType.Choices.OUTPUT.value))
         selection_template = models.TaskRelationSelectionTemplate.objects.get(name=task_relation_definition["selection_template"])
 
         try:
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/permissions.py b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/permissions.py
index 66124b5c3ba77f70eecd7533369037b9d1f5d88e..5ec90752626b1523eb195c883d84ee43bdc9900f 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/permissions.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/permissions.py
@@ -233,6 +233,10 @@ class IsProjectMemberFilterBackend(drf_filters.BaseFilterBackend):
         if view.action != 'list':
             return queryset
 
+        # if a system role allows general access to the model, do not filter
+        if TMSSDjangoModelPermissions().has_permission(request, view):
+            return queryset
+
         # we don't filer for superuser (e.g. in test environment, where a regular user is created to test filtering specifically)
         if request.user.is_superuser:
             logger.info("IsProjectMemberFilterBackend: User=%s is superuser. Not enforcing project permissions!" % request.user)
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py
index d53ace784b028f01ba199a80e067090526a66a41..620742eaa77f9aedd8400e88f862121fcb2e2dbf 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py
@@ -280,6 +280,11 @@ class RoleViewSet(LOFARViewSet):
     serializer_class = serializers.RoleSerializer
 
 
+class IOTypeViewSet(LOFARViewSet):
+    queryset = models.IOType.objects.all()
+    serializer_class = serializers.IOTypeSerializer
+
+
 class SchedulingRelationPlacement(LOFARViewSet):
     queryset = models.SchedulingRelationPlacement.objects.all()
     serializer_class = serializers.SchedulingRelationPlacementSerializer
diff --git a/SAS/TMSS/backend/src/tmss/urls.py b/SAS/TMSS/backend/src/tmss/urls.py
index 8e100460c33bb2b27c6ffb5d2fd930883c6abdc2..a0e44d185399b697c87218c9b055696d75202d2b 100644
--- a/SAS/TMSS/backend/src/tmss/urls.py
+++ b/SAS/TMSS/backend/src/tmss/urls.py
@@ -117,6 +117,7 @@ router.register(r'tags', viewsets.TagsViewSet)
 
 # choices
 router.register(r'role', viewsets.RoleViewSet)
+router.register(r'iotype', viewsets.IOTypeViewSet)
 router.register(r'datatype', viewsets.DatatypeViewSet)
 router.register(r'dataformat', viewsets.DataformatViewSet)
 router.register(r'copy_reason', viewsets.CopyReasonViewSet)
diff --git a/SAS/TMSS/backend/test/ldap_test_service.py b/SAS/TMSS/backend/test/ldap_test_service.py
index 308aa5ed76c8f910519f0730a123a5e14e412f64..6db66a2294d0d9f0e5e767d75203a48bbb7eb1e6 100644
--- a/SAS/TMSS/backend/test/ldap_test_service.py
+++ b/SAS/TMSS/backend/test/ldap_test_service.py
@@ -105,6 +105,86 @@ class TestLDAPServer():
                                                                    'mail': '%s@lofar.test' % self.dbcreds.user,
                                                                    'givenName': self.dbcreds.user,
                                                                    'sn': 'lofar_test'}},
+                                                   {'objectclass': 'lofarPerson',
+                                                    'dn': 'cn=to_observer,ou=users,o=lofar,c=eu',
+                                                    'attributes': {'cn': 'to_observer',
+                                                                   'userPassword': 'to_observer',
+                                                                   'mail': 'to_observer@astron.nl',
+                                                                   'givenName': 'to_observer',
+                                                                   'sn': 'to_observer',
+                                                                   'lofarPersonSystemrole': 'cn=support,ou=Roles,o=lofar,c=eu'}},
+                                                   {'objectclass': 'lofarPerson',
+                                                    'dn': 'cn=sdco_support,ou=users,o=lofar,c=eu',
+                                                    'attributes': {'cn': 'sdco_support',
+                                                                   'userPassword': 'sdco_support',
+                                                                   'mail': 'sdco_support@astron.nl',
+                                                                   'givenName': 'sdco_support',
+                                                                   'sn': 'sdco_support',
+                                                                   'lofarPersonSystemrole': 'cn=support,ou=Roles,o=lofar,c=eu'}},
+                                                   {'objectclass': 'lofarPerson',
+                                                    'dn': 'cn=tmss_maintainer,ou=users,o=lofar,c=eu',
+                                                    'attributes': {'cn': 'tmss_maintainer',
+                                                                   'userPassword': 'tmss_maintainer',
+                                                                   'mail': 'tmss_maintainer@astron.nl',
+                                                                   'givenName': 'tmss_maintainer',
+                                                                   'sn': 'tmss_maintainer',
+                                                                   'lofarPersonSystemrole': 'cn=support,ou=Roles,o=lofar,c=eu'}},
+                                                   {'objectclass': 'lofarPerson',
+                                                    'dn': 'cn=tmss_admin,ou=users,o=lofar,c=eu',
+                                                    'attributes': {'cn': 'tmss_admin',
+                                                                   'userPassword': 'tmss_admin',
+                                                                   'mail': 'tmss_admin@astron.nl',
+                                                                   'givenName': 'tmss_admin',
+                                                                   'sn': 'tmss_admin',
+                                                                   'lofarPersonSystemrole': 'cn=support,ou=Roles,o=lofar,c=eu'}},
+                                                   {'objectclass': 'lofarPerson',
+                                                    'dn': 'cn=to_maintenance,ou=users,o=lofar,c=eu',
+                                                    'attributes': {'cn': 'to_maintenance',
+                                                                   'userPassword': 'to_maintenance',
+                                                                   'mail': 'to_maintenance@astron.nl',
+                                                                   'givenName': 'to_maintenance',
+                                                                   'sn': 'to_maintenance',
+                                                                   'lofarPersonSystemrole': 'cn=support,ou=Roles,o=lofar,c=eu'}},
+                                                   {'objectclass': 'lofarPerson',
+                                                    'dn': 'cn=to_user,ou=users,o=lofar,c=eu',
+                                                    'attributes': {'cn': 'to_user',
+                                                                   'userPassword': 'to_user',
+                                                                   'mail': 'to_user@astron.nl',
+                                                                   'givenName': 'to_user',
+                                                                   'sn': 'to_user',
+                                                                   'lofarPersonSystemrole': 'cn=support,ou=Roles,o=lofar,c=eu'}},
+                                                   {'objectclass': 'lofarPerson',
+                                                    'dn': 'cn=scientist,ou=users,o=lofar,c=eu',
+                                                    'attributes': {'cn': 'scientist',
+                                                                   'userPassword': 'scientist',
+                                                                   'mail': 'scientist@astron.nl',
+                                                                   'givenName': 'scientist',
+                                                                   'sn': 'scientist',
+                                                                   'lofarPersonSystemrole': 'cn=support,ou=Roles,o=lofar,c=eu'}},
+                                                   {'objectclass': 'lofarPerson',
+                                                    'dn': 'cn=e_scientist,ou=users,o=lofar,c=eu',
+                                                    'attributes': {'cn': 'e_scientist',
+                                                                   'userPassword': 'e_scientist',
+                                                                   'mail': 'e_scientist@astron.nl',
+                                                                   'givenName': 'e_scientist',
+                                                                   'sn': 'e_scientist',
+                                                                   'lofarPersonSystemrole': 'cn=support,ou=Roles,o=lofar,c=eu'}},
+                                                   {'objectclass': 'lofarPerson',
+                                                    'dn': 'cn=guest,ou=users,o=lofar,c=eu',
+                                                    'attributes': {'cn': 'guest',
+                                                                   'userPassword': 'guest',
+                                                                   'mail': 'guest@astron.nl',
+                                                                   'givenName': 'guest',
+                                                                   'sn': 'guest',
+                                                                   'lofarPersonSystemrole': 'cn=support,ou=Roles,o=lofar,c=eu'}},
+                                                   {'objectclass': 'lofarPerson',
+                                                    'dn': 'cn=lta_user,ou=users,o=lofar,c=eu',
+                                                    'attributes': {'cn': 'lta_user',
+                                                                   'userPassword': 'lta_user',
+                                                                   'mail': 'lta_user@astron.nl',
+                                                                   'givenName': 'lta_user',
+                                                                   'sn': 'lta_user',
+                                                                   'lofarPersonSystemrole': 'cn=support,ou=Roles,o=lofar,c=eu'}},
                                                    {'objectclass': 'organizationUnit',
                                                     'dn': 'ou=Roles,o=lofar,c=eu',
                                                     'attributes': {'ou': 'Roles'}},
diff --git a/SAS/TMSS/backend/test/t_scheduling.py b/SAS/TMSS/backend/test/t_scheduling.py
index 5bcfa16e9e29e9e82b75a3c5f13dff663a89289d..6a6ff816fce2866f0f34a9c07c805aac6a83bf6c 100755
--- a/SAS/TMSS/backend/test/t_scheduling.py
+++ b/SAS/TMSS/backend/test/t_scheduling.py
@@ -408,7 +408,7 @@ class SchedulingTest(unittest.TestCase):
             # connect obs to pipeline
             scheduling_unit_doc['task_relations'].append({"producer": "Observation",
                                                           "consumer": "Pipeline",
-                                                          "input": { "role": "input", "datatype": "visibilities" },
+                                                          "input": { "role": "any", "datatype": "visibilities" },
                                                           "output": { "role": "correlator", "datatype": "visibilities" },
                                                           "dataformat": "MeasurementSet",
                                                           "selection_doc": {},
diff --git a/SAS/TMSS/backend/test/t_tmssapp_specification_REST_API.py b/SAS/TMSS/backend/test/t_tmssapp_specification_REST_API.py
index d3da150deaa98063eb7c714b99090c37447c8597..f0c8c331dc951757c7e98c3a3c90b467591446f7 100755
--- a/SAS/TMSS/backend/test/t_tmssapp_specification_REST_API.py
+++ b/SAS/TMSS/backend/test/t_tmssapp_specification_REST_API.py
@@ -577,8 +577,7 @@ class TaskRelationSelectionTemplateTestCase(unittest.TestCase):
 class TaskConnectorTestCase(unittest.TestCase):
     @classmethod
     def setUpClass(cls) -> None:
-        cls.input_of_url = test_data_creator.post_data_and_get_url(test_data_creator.TaskTemplate(), '/task_template/')
-        cls.output_of_url = test_data_creator.post_data_and_get_url(test_data_creator.TaskTemplate(), '/task_template/')
+        cls.task_template_url = test_data_creator.post_data_and_get_url(test_data_creator.TaskTemplate(), '/task_template/')
 
     def test_task_connector_list_apiformat(self):
         r = requests.get(BASE_URL + '/task_connector_type/?format=api', auth=AUTH)
@@ -589,7 +588,8 @@ class TaskConnectorTestCase(unittest.TestCase):
         GET_and_assert_equal_expected_code(self, BASE_URL + '/task_connector_type/1234321/', 404)
 
     def test_task_connector_POST_and_GET(self):
-        tc_test_data = test_data_creator.TaskConnectorType(input_of_url=self.input_of_url, output_of_url=self.output_of_url)
+        tc_test_data = test_data_creator.TaskConnectorType(task_template_url=self.task_template_url)
+
         # POST and GET a new item and assert correctness
         r_dict = POST_and_assert_expected_response(self, BASE_URL + '/task_connector_type/', tc_test_data, 201, tc_test_data)
         url = r_dict['url']
@@ -598,7 +598,7 @@ class TaskConnectorTestCase(unittest.TestCase):
     def test_task_connector_POST_invalid_role_raises_error(self):
 
         # POST a new item with invalid choice
-        test_data_invalid_role = dict(test_data_creator.TaskConnectorType(input_of_url=self.input_of_url, output_of_url=self.output_of_url))
+        test_data_invalid_role = dict(test_data_creator.TaskConnectorType(task_template_url=self.task_template_url))
         test_data_invalid_role['role'] = BASE_URL + '/role/forbidden/'
         r_dict = POST_and_assert_expected_response(self, BASE_URL + '/task_connector_type/', test_data_invalid_role, 400, {})
         self.assertTrue('Invalid hyperlink' in str(r_dict['role']))
@@ -606,7 +606,7 @@ class TaskConnectorTestCase(unittest.TestCase):
     def test_task_connector_POST_invalid_datatype_raises_error(self):
 
         # POST a new item with invalid choice
-        test_data_invalid = dict(test_data_creator.TaskConnectorType(input_of_url=self.input_of_url, output_of_url=self.output_of_url))
+        test_data_invalid = dict(test_data_creator.TaskConnectorType(task_template_url=self.task_template_url))
         test_data_invalid['datatype'] = BASE_URL + '/datatype/forbidden/'
         r_dict = POST_and_assert_expected_response(self, BASE_URL + '/task_connector_type/', test_data_invalid, 400, {})
         self.assertTrue('Invalid hyperlink' in str(r_dict['datatype']))
@@ -614,26 +614,18 @@ class TaskConnectorTestCase(unittest.TestCase):
     def test_task_connector_POST_invalid_dataformats_raises_error(self):
 
         # POST a new item with invalid choice
-        test_data_invalid = dict(test_data_creator.TaskConnectorType(input_of_url=self.input_of_url, output_of_url=self.output_of_url))
+        test_data_invalid = dict(test_data_creator.TaskConnectorType(task_template_url=self.task_template_url))
         test_data_invalid['dataformats'] = [BASE_URL + '/dataformat/forbidden/']
         r_dict = POST_and_assert_expected_response(self, BASE_URL + '/task_connector_type/', test_data_invalid, 400, {})
         self.assertTrue('Invalid hyperlink' in str(r_dict['dataformats']))
 
-    def test_task_connector_POST_nonexistant_input_of_raises_error(self):
+    def test_task_connector_POST_nonexistant_task_template_raises_error(self):
 
         # POST a new item with wrong reference
-        test_data_invalid = dict(test_data_creator.TaskConnectorType(input_of_url=self.input_of_url, output_of_url=self.output_of_url))
-        test_data_invalid['input_of'] = BASE_URL + "/task_template/6353748/"
+        test_data_invalid = dict(test_data_creator.TaskConnectorType(task_template_url=self.task_template_url))
+        test_data_invalid['task_template'] = BASE_URL + "/task_template/6353748/"
         r_dict = POST_and_assert_expected_response(self, BASE_URL + '/task_connector_type/', test_data_invalid, 400, {})
-        self.assertTrue('Invalid hyperlink' in str(r_dict['input_of']))
-
-    def test_task_connector_POST_nonexistant_output_of_raises_error(self):
-
-        # POST a new item with wrong reference
-        test_data_invalid = dict(test_data_creator.TaskConnectorType(input_of_url=self.input_of_url, output_of_url=self.output_of_url))
-        test_data_invalid['output_of'] = BASE_URL + "/task_template/6353748/"
-        r_dict = POST_and_assert_expected_response(self, BASE_URL + '/task_connector_type/', test_data_invalid, 400, {})
-        self.assertTrue('Invalid hyperlink' in str(r_dict['output_of']))
+        self.assertTrue('Invalid hyperlink' in str(r_dict['task_template']))
 
     def test_task_connector_POST_existing_outputs_works(self):
 
@@ -644,16 +636,16 @@ class TaskConnectorTestCase(unittest.TestCase):
         url = r_dict['url']
 
         # POST a new item with correct reference
-        test_data_valid = dict(test_data_creator.TaskConnectorType(input_of_url=self.input_of_url, output_of_url=self.output_of_url))
-        test_data_valid['output_of'] = url
+        test_data_valid = dict(test_data_creator.TaskConnectorType(task_template_url=self.task_template_url))
+        test_data_valid['task_template'] = url
         POST_and_assert_expected_response(self, BASE_URL + '/task_connector_type/', test_data_valid, 201, test_data_valid)
 
     def test_task_connector_PUT_nonexistant_raises_error(self):
-        PUT_and_assert_expected_response(self, BASE_URL + '/task_connector_type/9876789876/', test_data_creator.TaskConnectorType(input_of_url=self.input_of_url, output_of_url=self.output_of_url), 404, {})
+        PUT_and_assert_expected_response(self, BASE_URL + '/task_connector_type/9876789876/', test_data_creator.TaskConnectorType(task_template_url=self.task_template_url), 404, {})
 
     def test_task_connector_PUT(self):
-        tc_test_data1 = test_data_creator.TaskConnectorType(role="correlator", input_of_url=self.input_of_url, output_of_url=self.output_of_url)
-        tc_test_data2 = test_data_creator.TaskConnectorType(role="beamformer", input_of_url=self.input_of_url, output_of_url=self.output_of_url)
+        tc_test_data1 = test_data_creator.TaskConnectorType(role="correlator", task_template_url=self.task_template_url)
+        tc_test_data2 = test_data_creator.TaskConnectorType(role="beamformer", task_template_url=self.task_template_url)
 
         # POST new item, verify
         r_dict = POST_and_assert_expected_response(self, BASE_URL + '/task_connector_type/', tc_test_data1, 201, tc_test_data1)
@@ -665,7 +657,7 @@ class TaskConnectorTestCase(unittest.TestCase):
         GET_OK_and_assert_equal_expected_response(self, url, tc_test_data2)
 
     def test_task_connector_PATCH(self):
-        tc_test_data = test_data_creator.TaskConnectorType(input_of_url=self.input_of_url, output_of_url=self.output_of_url)
+        tc_test_data = test_data_creator.TaskConnectorType(task_template_url=self.task_template_url)
 
         # POST new item, verify
         r_dict = POST_and_assert_expected_response(self, BASE_URL + '/task_connector_type/', tc_test_data, 201, tc_test_data)
@@ -683,7 +675,7 @@ class TaskConnectorTestCase(unittest.TestCase):
         GET_OK_and_assert_equal_expected_response(self, url, expected_data)
 
     def test_task_connector_DELETE(self):
-        tc_test_data = test_data_creator.TaskConnectorType(input_of_url=self.input_of_url, output_of_url=self.output_of_url)
+        tc_test_data = test_data_creator.TaskConnectorType(task_template_url=self.task_template_url)
 
         # POST new item, verify
         r_dict = POST_and_assert_expected_response(self, BASE_URL + '/task_connector_type/', tc_test_data, 201, tc_test_data)
@@ -693,27 +685,15 @@ class TaskConnectorTestCase(unittest.TestCase):
         # DELETE and check it's gone
         DELETE_and_assert_gone(self, url)
 
-    def test_task_relation_blueprint_CASCADE_behavior_on_inputs_template_deleted(self):
-        input_of_url = test_data_creator.post_data_and_get_url(test_data_creator.TaskTemplate(), '/task_template/')
-        tc_test_data = test_data_creator.TaskConnectorType(input_of_url=input_of_url, output_of_url=self.output_of_url)
-        # POST new item
-        url = POST_and_assert_expected_response(self, BASE_URL + '/task_connector_type/', tc_test_data, 201, tc_test_data)['url']
-        # verify
-        GET_OK_and_assert_equal_expected_response(self, url, tc_test_data)
-        # DELETE dependency
-        DELETE_and_assert_gone(self, input_of_url)
-        # assert
-        GET_and_assert_equal_expected_code(self, url, 404)
-
-    def test_task_relation_blueprint_CASCADE_behavior_on_outputs_template_deleted(self):
-        output_of_url = test_data_creator.post_data_and_get_url(test_data_creator.TaskTemplate(), '/task_template/')
-        tc_test_data = test_data_creator.TaskConnectorType(input_of_url=self.input_of_url, output_of_url=output_of_url)
+    def test_task_relation_blueprint_CASCADE_behavior_on_template_deleted(self):
+        task_template_url = test_data_creator.post_data_and_get_url(test_data_creator.TaskTemplate(), '/task_template/')
+        tc_test_data = test_data_creator.TaskConnectorType(task_template_url=task_template_url)
         # POST new item
         url = POST_and_assert_expected_response(self, BASE_URL + '/task_connector_type/', tc_test_data, 201, tc_test_data)['url']
         # verify
         GET_OK_and_assert_equal_expected_response(self, url, tc_test_data)
         # DELETE dependency
-        DELETE_and_assert_gone(self, output_of_url)
+        DELETE_and_assert_gone(self, task_template_url)
         # assert
         GET_and_assert_equal_expected_code(self, url, 404)
 
diff --git a/SAS/TMSS/backend/test/t_tmssapp_specification_django_API.py b/SAS/TMSS/backend/test/t_tmssapp_specification_django_API.py
index 7966ebf804157257cddc5f6b63d1d774d20694ad..7ace3e3ad11b88a2c9f1e169c8b01b7dc8d5e57d 100755
--- a/SAS/TMSS/backend/test/t_tmssapp_specification_django_API.py
+++ b/SAS/TMSS/backend/test/t_tmssapp_specification_django_API.py
@@ -268,21 +268,11 @@ class TaskRelationSelectionTemplateTest(unittest.TestCase):
 
 class TaskConnectorTest(unittest.TestCase):
 
-    def test_POST_TaskConnector_prevents_missing_input_of(self):
+    def test_POST_TaskConnector_prevents_missing_task_template(self):
 
         # setup
         test_data_1 = dict(TaskConnectorType_test_data())
-        test_data_1['input_of'] = None
-
-        # assert
-        with self.assertRaises(IntegrityError):
-            models.TaskConnectorType.objects.create(**test_data_1)
-
-    def test_POST_TaskConnector_prevents_missing_output_of(self):
-
-        # setup
-        test_data_1 = dict(TaskConnectorType_test_data())
-        test_data_1['output_of'] = None
+        test_data_1['task_template'] = None
 
         # assert
         with self.assertRaises(IntegrityError):
diff --git a/SAS/TMSS/backend/test/tmss_test_data_django_models.py b/SAS/TMSS/backend/test/tmss_test_data_django_models.py
index c4c98b7f64b79b5aa6f7a1d4926e7ca7ecf68a2f..d9296ec1062f925af4bd73121f9886d337225926 100644
--- a/SAS/TMSS/backend/test/tmss_test_data_django_models.py
+++ b/SAS/TMSS/backend/test/tmss_test_data_django_models.py
@@ -106,8 +106,8 @@ def TaskRelationSelectionTemplate_test_data(name="my_TaskRelationSelectionTempla
 def TaskConnectorType_test_data() -> dict:
     return {"role": models.Role.objects.get(value='calibrator'),
             "datatype": models.Datatype.objects.get(value='instrument model'),
-            "output_of": models.TaskTemplate.objects.create(**TaskTemplate_test_data()),
-            "input_of": models.TaskTemplate.objects.create(**TaskTemplate_test_data()),
+            "task_template": models.TaskTemplate.objects.create(**TaskTemplate_test_data()),
+            "iotype": models.IOType.objects.get(value=models.IOType.Choices.OUTPUT.value),
             "tags": []}
 
 def Cycle_test_data() -> dict:
diff --git a/SAS/TMSS/backend/test/tmss_test_data_rest.py b/SAS/TMSS/backend/test/tmss_test_data_rest.py
index 046bc7fa6a34e02934d55b214a66a3164481c108..528e81dd5619d2a6318ec85696d55c3e058c0dea 100644
--- a/SAS/TMSS/backend/test/tmss_test_data_rest.py
+++ b/SAS/TMSS/backend/test/tmss_test_data_rest.py
@@ -221,18 +221,15 @@ class TMSSRESTTestDataCreator():
             return self._task_relation_selection_template_url
 
 
-    def TaskConnectorType(self, role="correlator", input_of_url=None, output_of_url=None):
-        if input_of_url is None:
-            input_of_url = self.cached_task_template_url
-    
-        if output_of_url is None:
-            output_of_url = self.cached_task_template_url
+    def TaskConnectorType(self, role="correlator", iotype="output", task_template_url=None):
+        if task_template_url is None:
+            task_template_url = self.cached_task_template_url
     
         return {"role": self.django_api_url + '/role/%s'%role,
                 "datatype": self.django_api_url + '/datatype/image',
                 "dataformats": [self.django_api_url + '/dataformat/Beamformed'],
-                "output_of": output_of_url,
-                "input_of": input_of_url,
+                "task_template": task_template_url,
+                "iotype": self.django_api_url + '/iotype/%s'%iotype,
                 "tags": []}
 
 
@@ -434,10 +431,10 @@ class TMSSRESTTestDataCreator():
             selection_doc = self.get_response_as_json_object(template_url+'/default')
 
         if input_role_url is None:
-            input_role_url = self.post_data_and_get_url(self.TaskConnectorType(), '/task_connector_type/')
+            input_role_url = self.post_data_and_get_url(self.TaskConnectorType(iotype="input"), '/task_connector_type/')
     
         if output_role_url is None:
-            output_role_url = self.post_data_and_get_url(self.TaskConnectorType(), '/task_connector_type/')
+            output_role_url = self.post_data_and_get_url(self.TaskConnectorType(iotype="output"), '/task_connector_type/')
     
         return {"tags": [],
                 "selection_doc": selection_doc,
@@ -533,10 +530,10 @@ class TMSSRESTTestDataCreator():
             selection_doc = self.get_response_as_json_object(template_url+'/default')
 
         if input_role_url is None:
-            input_role_url = self.post_data_and_get_url(self.TaskConnectorType(), '/task_connector_type/')
+            input_role_url = self.post_data_and_get_url(self.TaskConnectorType(iotype="input"), '/task_connector_type/')
     
         if output_role_url is None:
-            output_role_url = self.post_data_and_get_url(self.TaskConnectorType(), '/task_connector_type/')
+            output_role_url = self.post_data_and_get_url(self.TaskConnectorType(iotype="output"), '/task_connector_type/')
     
         # test data
         return {"tags": [],
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/App.js b/SAS/TMSS/frontend/tmss_webapp/src/App.js
index 74a6f8c2bd0dc57fea26971a4d83c1bf3d076c4b..f7800c0f6da31b54be802cfb909310de8fc8a4f3 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/App.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/App.js
@@ -34,7 +34,8 @@ class App extends Component {
         overlayMenuActive: localStorage.getItem('overlayMenuActive') === 'true' ? true : false,
         mobileMenuActive: localStorage.getItem('mobileMenuActive') === 'true' ? true : false,
         authenticated: Auth.isAuthenticated(),
-        redirect: (Auth.isAuthenticated() && window.location.pathname === "/login")?"/":window.location.pathname
+        redirect: (Auth.isAuthenticated() && window.location.pathname === "/login")?"/":window.location.pathname,
+        findObjectPlaceholder: 'Sub Task',
         };
         this.onWrapperClick = this.onWrapperClick.bind(this);
         this.onToggleMenu = this.onToggleMenu.bind(this);
@@ -43,13 +44,15 @@ class App extends Component {
         this.setPageTitle = this.setPageTitle.bind(this);
         this.loggedIn = this.loggedIn.bind(this);
         this.logout = this.logout.bind(this);
+        this.setSearchField = this.setSearchField.bind(this);
 
         this.menu = [ {label: 'Dashboard', icon: 'pi pi-fw pi-home', to:'/dashboard',section: 'dashboard'},
                         {label: 'Cycle', icon:'pi pi-fw pi-spinner', to:'/cycle',section: 'cycle'},
                         {label: 'Project', icon: 'fab fa-fw fa-wpexplorer', to:'/project',section: 'project'},
                         {label: 'Scheduling Units', icon: 'pi pi-fw pi-calendar', to:'/schedulingunit',section: 'schedulingunit'},
+                        {label: 'Tasks', icon: 'pi pi-fw pi-check-square', to:'/task'},
                         {label: 'Timeline', icon: 'pi pi-fw pi-clock', to:'/su/timelineview',section: 'su/timelineview'},
-                        //   {label: 'Tasks', icon: 'pi pi-fw pi-check-square', to:'/task'},
+                      
                     ];
     }
 
@@ -130,6 +133,19 @@ class App extends Component {
         this.setState({authenticated: false, redirect:"/"});
     }
 
+    /**
+     * Set search param
+     * @param {*} key 
+     * @param {*} value 
+     */
+    setSearchField(key, value) {
+        this.setState({
+            objectType: key, 
+            findObjectId: value, 
+            redirect:"/find/object/"+key+"/"+value
+        });
+    }
+
     render() {
         const wrapperClass = classNames('layout-wrapper', {
             'layout-overlay': this.state.layoutMode === 'overlay',
@@ -150,12 +166,17 @@ class App extends Component {
                     {/* Load main routes and application only if the application is authenticated */}
                     {this.state.authenticated &&
                     <>
-                        <AppTopbar onToggleMenu={this.onToggleMenu} isLoggedIn={this.state.authenticated} onLogout={this.logout}></AppTopbar>
+                        <AppTopbar 
+                            onToggleMenu={this.onToggleMenu} 
+                            isLoggedIn={this.state.authenticated} 
+                            onLogout={this.logout} 
+                            setSearchField={this.setSearchField}
+                        />
                         <Router basename={ this.state.currentPath }>
                             <AppMenu model={this.menu} onMenuItemClick={this.onMenuItemClick} layoutMode={this.state.la} active={this.state.menuActive}/>
                             <div className="layout-main">
                                 {this.state.redirect &&
-                                    <Redirect to={{pathname: this.state.redirect}} />}
+                                    <Redirect to={{pathname: this.state.redirect }}/> }
                                 <AppBreadCrumbWithRouter setPageTitle={this.setPageTitle} />
                                 <RoutedContent />
                             </div>
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 19ee68919a9d2397e8e4691152bc713246427d73..237eefd86136b5d7ee9fcd14b08528f5413962bf 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/components/Timeline/CalendarTimeline.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/components/Timeline/CalendarTimeline.js
@@ -170,6 +170,10 @@ export class CalendarTimeline extends Component {
         return true;
     }
 
+    componentWillUnmount() {
+        this.componentUnmounting = true;        // Variable to check and terminate any API calls in loop
+    }
+
     /**
      * Sets current UTC and LST time either from the server or locally.
      * @param {boolean} systemClock - to differetiate whether tosync with server or local update
@@ -719,7 +723,7 @@ export class CalendarTimeline extends Component {
                 zIndex: item.type==="SUNTIME"?79:80
               },
               onMouseDown: () => {
-                  if (item.type !== "SUNTIME" && item.type !== "RESERVATION") {
+                  if (item.type !== "SUNTIME") {
                     this.onItemClick(item);
                   } else {
 
@@ -814,7 +818,9 @@ export class CalendarTimeline extends Component {
      * @param {Object} item 
      */
     onItemMouseOver(evt, item) {
-        if ((item.type==="SCHEDULE" || item.type==="TASK") && this.props.itemMouseOverCallback) {
+        if ((item.type==="SCHEDULE" || item.type==="TASK" || item.type==="RESERVATION") 
+                && this.props.itemMouseOverCallback) {
+            this.setState({mouseEvent: true});
             this.props.itemMouseOverCallback(evt, item);
         }
     }
@@ -824,7 +830,9 @@ export class CalendarTimeline extends Component {
      * @param {Object} item 
      */
     onItemMouseOut(evt, item) {
-        if ((item.type==="SCHEDULE" || item.type==="TASK") && this.props.itemMouseOutCallback) {
+        if ((item.type==="SCHEDULE" || item.type==="TASK"|| item.type==="RESERVATION") 
+                && this.props.itemMouseOutCallback) {
+            this.setState({mouseEvent: true});
             this.props.itemMouseOutCallback(evt);
         }
     }
@@ -835,13 +843,14 @@ export class CalendarTimeline extends Component {
      * @param {moment} endTime 
      */
     async changeDateRange(startTime, endTime, refreshData) {
-        if (this.props.showSunTimings && this.state.viewType===UIConstants.timeline.types.NORMAL) {
+        if (this.props.showSunTimings && this.state.viewType===UIConstants.timeline.types.NORMAL && !this.loadingNormalSuntimes) {
             this.setNormalSuntimings(startTime, endTime);
         }
         const result = await this.props.dateRangeCallback(startTime, endTime, refreshData);
-        if (!this.props.showSunTimings && this.state.viewType === UIConstants.timeline.types.NORMAL) {
+        if (!this.props.showSunTimings && this.state.viewType === UIConstants.timeline.types.NORMAL && !this.loadingStationSunTimes) {
             result.items = await this.addStationSunTimes(startTime, endTime, result.group, result.items);
-        }   else if (this.state.viewType === UIConstants.timeline.types.WEEKVIEW) {
+            result.items = _.orderBy(result.items, ['type'], ['desc']);
+        }   else if (this.state.viewType === UIConstants.timeline.types.WEEKVIEW && !this.loadingWeekSunTimes) {
             let group = DEFAULT_GROUP.concat(result.group);
             result.items = await this.addWeekSunTimes(startTime, endTime, group, result.items);
         }
@@ -853,14 +862,16 @@ export class CalendarTimeline extends Component {
      * @param {moment} startTime 
      * @param {moment} endTime 
      */
-    setNormalSuntimings(startTime, endTime) {
+    async setNormalSuntimings(startTime, endTime) {
         let sunRiseTimings = [], sunSetTimings = [], sunTimeMap={};
         const noOfDays = endTime.diff(startTime, 'days');
-        for (const number of _.range(noOfDays+3)) {                     // Added 3 to have suntimes of day before start time and day after end time so that for small time duration also, suntimes will be available.
-            let prevStartTime = startTime.clone().add(-1, 'days');
-            const date = prevStartTime.clone().add(number, 'days').hours(12).minutes(0).seconds(0);
-            const formattedDate = date.format("YYYY-MM-DD");
-            UtilService.getSunTimings(formattedDate).then(timings => {
+        if (!this.loadingNormalSuntimes) {
+            this.loadingNormalSuntimes = true;
+            for (const number of _.range(noOfDays+3)) {                     // Added 3 to have suntimes of day before start time and day after end time so that for small time duration also, suntimes will be available.
+                let prevStartTime = startTime.clone().add(-1, 'days');
+                const date = prevStartTime.clone().add(number, 'days').hours(12).minutes(0).seconds(0);
+                const formattedDate = date.format("YYYY-MM-DD");
+                let timings = await UtilService.getSunTimings(formattedDate);
                 if (timings) {
                     const sunriseStartTime = moment.utc(timings.sun_rise.start.split('.')[0]);
                     const sunriseEndTime = moment.utc(timings.sun_rise.end.split('.')[0]);
@@ -877,7 +888,10 @@ export class CalendarTimeline extends Component {
                     sunTimeMap[formattedDate] = {sunrise: sunriseTime, sunset: sunsetTime};
                     this.setState({sunRiseTimings: sunRiseTimings, sunSetTimings: sunSetTimings, sunTimeMap: sunTimeMap});
                 }
-            });
+                if (number === (noOfDays+2)) {
+                    this.loadingNormalSuntimes = false;
+                }
+            }
         }
     }
 
@@ -891,78 +905,84 @@ export class CalendarTimeline extends Component {
     async addStationSunTimes(startTime, endTime, stationGroup, items) {
         const noOfDays = endTime.diff(startTime, 'days');
         let sunItems = _.cloneDeep(items);
+        this.loadingStationSunTimes = true;
         for (const number of _.range(noOfDays+1)) {
             for (const station of stationGroup) {
-                const date = startTime.clone().add(number, 'days').hours(12).minutes(0).seconds(0);
-                const timings = await UtilService.getSunTimings(date.format("YYYY-MM-DD"), station.id);
-                if (timings) {
-                    let sunriseItem = { id: `sunrise-${number}-${station.id}`, 
-                                        group: station.id,
-                                        // title: `${timings.sun_rise.start} to ${timings.sun_rise.end}`,
-                                        title: "",
-                                        project: "",
-                                        name: "",
-                                        duration: "",
-                                        start_time: moment.utc(timings.sun_rise.start),
-                                        end_time: moment.utc(timings.sun_rise.end),
-                                        bgColor: "yellow",
-                                        selectedBgColor: "yellow",
-                                        type: "SUNTIME"};
-                    sunItems.push(sunriseItem);
-                    let sunsetItem = _.cloneDeep(sunriseItem);
-                    sunsetItem.id = `sunset-${number}-${station.id}`;
-                    // sunsetItem.title = `${timings.sun_set.start} to ${timings.sun_set.end}`;
-                    sunsetItem.title = "";
-                    sunsetItem.start_time = moment.utc(timings.sun_set.start);
-                    sunsetItem.end_time = moment.utc(timings.sun_set.end);
-                    sunsetItem.bgColor = "orange";
-                    sunsetItem.selectedBgColor = "orange";
-                    sunItems.push(sunsetItem);
-                    let befSunriseItem = _.cloneDeep(sunriseItem);
-                    befSunriseItem.id = `bef-sunrise-${number}-${station.id}`;
-                    // sunsetItem.title = `${timings.sun_set.start} to ${timings.sun_set.end}`;
-                    befSunriseItem.title = "";
-                    befSunriseItem.start_time = moment.utc(timings.sun_rise.start).hours(0).minutes(0).seconds(0);
-                    befSunriseItem.end_time = moment.utc(timings.sun_rise.start);
-                    befSunriseItem.bgColor = "grey";
-                    befSunriseItem.selectedBgColor = "grey";
-                    sunItems.push(befSunriseItem);
-                    let afterSunsetItem = _.cloneDeep(sunriseItem);
-                    afterSunsetItem.id = `aft-sunset-${number}-${station.id}`;
-                    // sunsetItem.title = `${timings.sun_set.start} to ${timings.sun_set.end}`;
-                    afterSunsetItem.title = "";
-                    afterSunsetItem.start_time = moment.utc(timings.sun_set.end);
-                    afterSunsetItem.end_time = moment.utc(timings.sun_set.end).hours(23).minutes(59).seconds(59);
-                    afterSunsetItem.bgColor = "grey";
-                    afterSunsetItem.selectedBgColor = "grey";
-                    sunItems.push(afterSunsetItem);
-                    let dayItem = _.cloneDeep(sunriseItem);
-                    dayItem.id = `day-${number}-${station.id}`;
-                    // sunsetItem.title = `${timings.sun_set.start} to ${timings.sun_set.end}`;
-                    dayItem.title = "";
-                    dayItem.start_time = moment.utc(timings.sun_rise.end);
-                    dayItem.end_time = moment.utc(timings.sun_set.start);
-                    dayItem.bgColor = "white";
-                    dayItem.selectedBgColor = "white";
-                    sunItems.push(dayItem);
+                if (!this.componentUnmounting) {
+                    const date = startTime.clone().add(number, 'days').hours(12).minutes(0).seconds(0);
+                    const timings = await UtilService.getSunTimings(date.format("YYYY-MM-DD"), station.id);
+                    if (timings) {
+                        let sunriseItem = { id: `sunrise-${number}-${station.id}`, 
+                                            group: station.id,
+                                            // title: `${timings.sun_rise.start} to ${timings.sun_rise.end}`,
+                                            title: "",
+                                            project: "",
+                                            name: "",
+                                            duration: "",
+                                            start_time: moment.utc(timings.sun_rise.start),
+                                            end_time: moment.utc(timings.sun_rise.end),
+                                            bgColor: "yellow",
+                                            selectedBgColor: "yellow",
+                                            type: "SUNTIME"};
+                        sunItems.push(sunriseItem);
+                        let sunsetItem = _.cloneDeep(sunriseItem);
+                        sunsetItem.id = `sunset-${number}-${station.id}`;
+                        // sunsetItem.title = `${timings.sun_set.start} to ${timings.sun_set.end}`;
+                        sunsetItem.title = "";
+                        sunsetItem.start_time = moment.utc(timings.sun_set.start);
+                        sunsetItem.end_time = moment.utc(timings.sun_set.end);
+                        sunsetItem.bgColor = "orange";
+                        sunsetItem.selectedBgColor = "orange";
+                        sunItems.push(sunsetItem);
+                        let befSunriseItem = _.cloneDeep(sunriseItem);
+                        befSunriseItem.id = `bef-sunrise-${number}-${station.id}`;
+                        // sunsetItem.title = `${timings.sun_set.start} to ${timings.sun_set.end}`;
+                        befSunriseItem.title = "";
+                        befSunriseItem.start_time = moment.utc(timings.sun_rise.start).hours(0).minutes(0).seconds(0);
+                        befSunriseItem.end_time = moment.utc(timings.sun_rise.start);
+                        befSunriseItem.bgColor = "grey";
+                        befSunriseItem.selectedBgColor = "grey";
+                        sunItems.push(befSunriseItem);
+                        let afterSunsetItem = _.cloneDeep(sunriseItem);
+                        afterSunsetItem.id = `aft-sunset-${number}-${station.id}`;
+                        // sunsetItem.title = `${timings.sun_set.start} to ${timings.sun_set.end}`;
+                        afterSunsetItem.title = "";
+                        afterSunsetItem.start_time = moment.utc(timings.sun_set.end);
+                        afterSunsetItem.end_time = moment.utc(timings.sun_set.end).hours(23).minutes(59).seconds(59);
+                        afterSunsetItem.bgColor = "grey";
+                        afterSunsetItem.selectedBgColor = "grey";
+                        sunItems.push(afterSunsetItem);
+                        let dayItem = _.cloneDeep(sunriseItem);
+                        dayItem.id = `day-${number}-${station.id}`;
+                        // sunsetItem.title = `${timings.sun_set.start} to ${timings.sun_set.end}`;
+                        dayItem.title = "";
+                        dayItem.start_time = moment.utc(timings.sun_rise.end);
+                        dayItem.end_time = moment.utc(timings.sun_set.start);
+                        dayItem.bgColor = "white";
+                        dayItem.selectedBgColor = "white";
+                        sunItems.push(dayItem);
+                    }   else {
+                        /* If no sunrise and sunset, show it as night time. Later it should be done as either day or night. */
+                        let befSunriseItem = { id: `bef-sunrise-${number}-${station.id}`, 
+                                            group: station.id,
+                                            // title: `${timings.sun_rise.start} to ${timings.sun_rise.end}`,
+                                            title: "",
+                                            project: "",
+                                            name: "",
+                                            duration: "",
+                                            start_time: moment.utc(date.format("YYYY-MM-DD 00:00:00")),
+                                            end_time: moment.utc(date.format("YYYY-MM-DD 23:59:59")),
+                                            bgColor: "grey",
+                                            selectedBgColor: "grey",
+                                            type: "SUNTIME"};
+                        sunItems.push(befSunriseItem);
+                    }
                 }   else {
-                    /* If no sunrise and sunset, show it as night time. Later it should be done as either day or night. */
-                    let befSunriseItem = { id: `bef-sunrise-${number}-${station.id}`, 
-                                        group: station.id,
-                                        // title: `${timings.sun_rise.start} to ${timings.sun_rise.end}`,
-                                        title: "",
-                                        project: "",
-                                        name: "",
-                                        duration: "",
-                                        start_time: moment.utc(date.format("YYYY-MM-DD 00:00:00")),
-                                        end_time: moment.utc(date.format("YYYY-MM-DD 23:59:59")),
-                                        bgColor: "grey",
-                                        selectedBgColor: "grey",
-                                        type: "SUNTIME"};
-                    sunItems.push(befSunriseItem);
+                    break;
                 }
             }
         }
+        this.loadingStationSunTimes = false;
         if (!this.props.showSunTimings && this.state.viewType === UIConstants.timeline.types.NORMAL) {
             items = sunItems;
         }
@@ -978,6 +998,7 @@ export class CalendarTimeline extends Component {
      */
     async addWeekSunTimes(startTime, endTime, weekGroup, items) {
         let sunItems = _.cloneDeep(items);
+        this.loadingWeekSunTimes = true;
         for (const weekDay of weekGroup) {
             if (weekDay.value) {
                 const timings = await UtilService.getSunTimings(weekDay.value.format("YYYY-MM-DD"), 'CS001');
@@ -1028,6 +1049,7 @@ export class CalendarTimeline extends Component {
                     sunItems.push(afterSunsetItem);
                 }
             }
+            this.loadingWeekSunTimes = false;
         }
         if (this.state.viewType === UIConstants.timeline.types.WEEKVIEW) {
             items = _.orderBy(sunItems, ['type'], ['desc']);
@@ -1245,22 +1267,26 @@ export class CalendarTimeline extends Component {
      * @param {Object} props 
      */
     async updateTimeline(props) {
-        this.setState({ showSpinner: true });
-        let group =  DEFAULT_GROUP.concat(props.group);
-        if (!this.props.showSunTimings && this.state.viewType === UIConstants.timeline.types.NORMAL) {
-            props.items = await this.addStationSunTimes(this.state.defaultStartTime, this.state.defaultEndTime, props.group, props.items);
-        }   else if(this.props.showSunTimings && this.state.viewType === UIConstants.timeline.types.NORMAL) {
-            this.setNormalSuntimings(this.state.defaultStartTime, this.state.defaultEndTime);
-        }   else if (this.state.viewType === UIConstants.timeline.types.WEEKVIEW) {
-            props.items = await this.addWeekSunTimes(this.state.defaultStartTime, this.state.defaultEndTime, group, props.items);
+        if (!this.state.mouseEvent) { // No need to update timeline items for mouseover and mouseout events
+            // this.setState({ showSpinner: true });
+            let group =  DEFAULT_GROUP.concat(props.group);
+            if (!this.props.showSunTimings && this.state.viewType === UIConstants.timeline.types.NORMAL && !this.loadingStationSunTimes) {
+                props.items = await this.addStationSunTimes(this.state.defaultStartTime, this.state.defaultEndTime, props.group, props.items);
+            }   else if(this.props.showSunTimings && this.state.viewType === UIConstants.timeline.types.NORMAL && !this.loadingNormalSuntimes) {
+                this.setNormalSuntimings(this.state.defaultStartTime, this.state.defaultEndTime);
+            }   else if (this.state.viewType === UIConstants.timeline.types.WEEKVIEW && !this.loadingWeekSunTimes) {
+                props.items = await this.addWeekSunTimes(this.state.defaultStartTime, this.state.defaultEndTime, group, props.items);
+            }
+            this.setState({group: group, showSpinner: false, items: _.orderBy(props.items, ['type'], ['desc'])});
+        }   else {
+            this.setState({mouseEvent: false});
         }
-        this.setState({group: group, showSpinner: false, items: _.orderBy(props.items, ['type'], ['desc'])});
     }
 
     render() {
         return (
             <React.Fragment>
-                <CustomPageSpinner visible={this.state.showSpinner} />
+                {/* <CustomPageSpinner visible={this.state.showSpinner} /> */}
                 {/* Toolbar for the timeline */}
                 <div className={`p-fluid p-grid timeline-toolbar ${this.props.className}`}>
                     {/* Clock Display */}
@@ -1345,7 +1371,7 @@ export class CalendarTimeline extends Component {
                             <div className='col-1 su-legend su-finished' title="Finished">Finished</div>
                         </div>
                     </div>
-                    {!this.props.showSunTimings && this.state.viewType===UIConstants.timeline.types.NORMAL &&
+                    {!this.props.showSunTimings && 
                     <div className="col-3">
                         <div style={{fontWeight:'500', height: '25px'}}>Station Reservation</div>
                         <div className="p-grid">
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/components/ViewTable.js b/SAS/TMSS/frontend/tmss_webapp/src/components/ViewTable.js
index b0202b05cf33dda39dc34f4d273b4c9530976897..e4709c550415ae27ab9207f2e503cf6626fb6dce 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/components/ViewTable.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/components/ViewTable.js
@@ -974,14 +974,18 @@ function ViewTable(props) {
     })
   }
 
-  const navigateTo = (props) => () => {
-    if (props.cell.row.values['actionpath']) {
-      return history.push({
-        pathname: props.cell.row.values['actionpath'],
-        state: {
-          "id": props.value,
-        }
-      })
+  const navigateTo = (cellProps) => () => {
+    if (cellProps.cell.row.values['actionpath']) {
+      if (!props.viewInNewWindow) {
+        return history.push({
+          pathname: cellProps.cell.row.values['actionpath'],
+          state: {
+            "id": cellProps.value,
+          }
+        })
+      } else {
+        window.open(cellProps.cell.row.values['actionpath'] , '_blank');
+      }
     }
     // Object.entries(props.paths[0]).map(([key,value]) =>{})
   }
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/components/AppTopbar.js b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/AppTopbar.js
index f112943d779cdedc9448a0f7ff2f42ce10fab3c2..6625eb1ea1cb57c76a93d7f35e14ce598edd2a98 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/layout/components/AppTopbar.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/AppTopbar.js
@@ -5,19 +5,17 @@ import 'primereact/resources/themes/nova-light/theme.css';
 import 'primereact/resources/primereact.css';
 import 'primeflex/primeflex.css';
 import { PropTypes } from 'prop-types';
-
 import Auth from '../../authenticate/auth';
-
+import { FindObject } from './FindObject';
 export class AppTopbar extends Component {
 
     constructor(props) {
         super(props);
         this.state = {
-            username: Auth.getUser().name
+            username: Auth.getUser().name,
         };
     }
         
-    
     static defaultProps = {
         onToggleMenu: null
     }
@@ -31,9 +29,11 @@ export class AppTopbar extends Component {
             <React.Fragment>
                 <div className="layout-wrapper layout-static layout-static-sidebar-inactive">
                     <div className="layout-topbar clearfix">
+                        
                         <button className="p-link layout-menu-button" onClick={this.props.onToggleMenu}>
 						<i className="pi pi-bars"></i></button>
                         <span className="header-title">TMSS</span>
+                       
                         {this.props.isLoggedIn &&
                             <div className="top-right-bar">
                                 <span><i className="fa fa-user"></i>{this.state.username}</span>
@@ -41,6 +41,7 @@ export class AppTopbar extends Component {
                                 <i className="pi pi-power-off"></i></button>
                             </div>
                         }
+                       <FindObject setSearchField={this.props.setSearchField} />
                     </div>
                         
                 </div>
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/components/FindObject.js b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/FindObject.js
new file mode 100644
index 0000000000000000000000000000000000000000..530ba4d002023dce0d7dacdd940e4d5db175c50e
--- /dev/null
+++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/FindObject.js
@@ -0,0 +1,109 @@
+import React, {Component} from 'react';
+import { Dropdown } from 'primereact/dropdown';
+import _ from 'lodash';
+import { appGrowl , setAppGrowl } from './AppGrowl';
+import { Growl } from 'primereact/components/growl/Growl';
+import { InputText } from 'primereact/inputtext';
+
+export class FindObject extends Component {
+
+    constructor(props) {
+        super(props);
+        this.state = {
+            // Find Object - dropdown list value
+            objectTypes: [
+                {name: 'Scheduling Unit', code: 'sublueprint'},
+                {name: 'Task', code: 'taskblueprint'},
+                {name: 'Subtask', code: 'subtask'},
+               // {name: 'Task Draft', code: 'taskdraft'},
+                //{name: 'SU Draft', code: 'sudraft'},
+                // {name: 'Project', code: 'project'},
+            ],
+            objectId: '',
+            objectType:  {name: 'Scheduling Unit', code: 'sublueprint'}
+        };
+        this.findObject = this.findObject.bind(this);
+        this.setObjectType = this.setObjectType.bind(this);
+        this.setFindObjectId = this.setFindObjectId.bind(this);
+        this.handleEvent = this.handleEvent.bind(this);
+    }
+
+    /**
+     * 
+     * @param {Key Event} e - Key code
+     */
+    handleEvent(e) {
+        var key = e.which || e.keyCode;
+        if(key === 13 || key === 'Enter') {
+            this.findObject();
+        }
+    }
+    
+    /**
+     * Set Object Type
+     * @param {String} value - Object type value
+     */
+    setObjectType(value) {
+        if (value.name && value.name === 'Project') {
+            this.setState({objectType: value});
+        }   else if(isNaN(this.state.objectId)){
+            this.setState({objectType: value, objectId: ''});
+        }   else {
+            this.setState({objectType: value});
+        }
+    }
+
+    /**
+     * Set Object id value
+     * @param {String/Number} value - Object id, accepts alphanumeric if object type is 'Project'
+     */
+    setFindObjectId(value) {
+        if (this.state.objectType.name === 'Project' || !isNaN(value)) {
+            this.setState({objectId: value});
+        }   else{
+            appGrowl.show({severity: 'info', summary: 'Information', detail: 'Enter valid object Id'});
+        }
+    }
+        
+    /**
+     * Callback function to find Object
+     */
+    findObject() {
+        if (this.state.objectId && this.state.objectId.length > 0) {
+            this.props.setSearchField(this.state.objectType.code, this.state.objectId);
+        }   else {
+            appGrowl.show({severity: 'info', summary: 'Information', detail: 'Enter Object Id'});
+        }
+    }
+
+    render() {
+        return (
+            <React.Fragment>
+                <Growl ref={(el) => setAppGrowl(el)} />
+                <div className="top-right-bar find-object-search" style={{marginRight: '1em'}}>
+                    <Dropdown  
+                        className="p-link layout-menu-button find-object-type" 
+                        value={this.state.objectType} 
+                        options={this.state.objectTypes}   
+                        optionLabel="name"  
+                        onChange={(e) => {this.setObjectType(e.value)}}
+                    />
+                    
+                    
+                    <InputText 
+                        value={this.state.objectId} 
+                        onChange={(e) => {this.setFindObjectId(e.target.value)}} 
+                        title='Enter Object Id to search Object'
+                        className="find-object-search-input"  
+                        placeholder="Search by ID" 
+                        onKeyDown={this.handleEvent}
+                    />
+                    <button  className="p-link layout-menu-button" style={{float: 'right'}} onClick={this.findObject} >
+                        <i className="pi pi-search find-object-search-btn" />
+                    </button>
+                    
+                </div>
+            </React.Fragment>
+        );
+    }
+}
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_content.scss b/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_content.scss
index 5c49ad86c0d840f2b6876fd5662d5ca981e34331..16fda99097df01c69485d146d9d0bb3940775d50 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_content.scss
+++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_content.scss
@@ -3,4 +3,9 @@
     padding: 60px 16px 16px 25px;
     min-height: 95vh;
     background-color: white;
+}
+
+.find-obj-tree-view {
+    margin-left: 1em;
+    margin-right: 1em;
 }
\ No newline at end of file
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 7cf493ad504c52e7f507c474d121e00df44f57e1..e9e71c99a8042f651bc6227ef639e90b6f6841b5 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_timeline.scss
+++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_timeline.scss
@@ -242,7 +242,7 @@
     color: white;
 }
 
-.reserve.dynamic {
+.reserve-dynamic {
     background-color: #9b9999;
     color: white;
 }
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_topbar.scss b/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_topbar.scss
index 6c190d5e90b4061687c6da38aa6fdc6f3246ccfb..a7a0ff6d53998a391bc5b943bc20ba5f4b133170 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_topbar.scss
+++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_topbar.scss
@@ -118,9 +118,10 @@
         color: $topbarItemColor;
         @include transition(color $transitionDuration);
 
-        span {
+        // Search type dropdown arrow looks bigger in topbar,
+       /* span {
             font-size: 2em;
-        }
+        }*/
 
         &:hover {
             color: $topbarItemHoverColor;
@@ -143,4 +144,30 @@
 
 .top-right-bar button {
     padding-left: 5px;
-}
\ No newline at end of file
+}
+
+.find-object-search {
+    padding-top: 0px;
+   
+}
+
+.find-object-search-input {
+    border-inline-start-width: 0px;
+    border-inline-end-width: 2em !important;
+    width: 11em;
+}
+
+.find-object-search-btn {
+    display: inline-block;
+    right: 27px;
+    position: relative;
+    top: 6px;
+    color: darkblue;
+}
+
+.find-object-type {
+    width: 12em;
+    right:1em;
+}
+
+ 
\ No newline at end of file
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 0fd8c88cce18cf3a98c9006ee9d86ae2124d2fb7..c8784e6282287e5a80e6deccb958f7e5a77e3d31 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/summary.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/summary.js
@@ -58,6 +58,12 @@ export class SchedulingUnitSummary extends Component {
         if (constraint) {
             const objectType = typeof constraint;
             switch(objectType) {
+                case "number": {
+                    if ((constraint+"").indexOf(".")>=0) {
+                        constraint = parseFloat(constraint.toFixed(2));
+                    }
+                    break;
+                }
                 case "string": {
                     try {
                         const dateConstraint = moment.utc(constraint);
@@ -112,6 +118,15 @@ export class SchedulingUnitSummary extends Component {
         this.setState({constraintsDoc: jsonOutput});
     }
 
+    redirectToSUDetails = () => {
+        if (!this.props.viewInNewWindow) {
+            this.props.history.push(`/schedulingunit/view/blueprint/${this.props.schedulingUnit.id}`);
+        } else {
+            window.open(`/schedulingunit/view/blueprint/${this.props.schedulingUnit.id}`, '_blank');
+        }
+    }
+
+
     render() {
         const schedulingUnit = this.props.schedulingUnit;
         const suTaskList = this.props.suTaskList;
@@ -124,7 +139,7 @@ export class SchedulingUnitSummary extends Component {
             { schedulingUnit &&
                 <div className="p-grid timeline-details-pane" style={{marginTop: '10px'}}>
                     <h6 className="col-lg-10 col-sm-10">Details</h6>
-                    <Link to={`/schedulingunit/view/blueprint/${schedulingUnit.id}`} title="View Full Details"><i className="fa fa-eye"></i></Link>
+                    <Link onClick={this.redirectToSUDetails} title="View Full Details"><i className="fa fa-eye"></i></Link>
                     <Link to={this.props.location?this.props.location.pathname:"/su/timelineview"} onClick={this.closeSUDets} title="Close Details"><i className="fa fa-times"></i></Link>
                     <div className="col-4"><label>Name:</label></div>
                     <div className="col-8">{schedulingUnit.name}</div>
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Search/find.object.result.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Search/find.object.result.js
new file mode 100644
index 0000000000000000000000000000000000000000..d341e5e30893b8fee51cdd2e253028804c5949a8
--- /dev/null
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Search/find.object.result.js
@@ -0,0 +1,231 @@
+import React, {Component} from 'react';
+import PageHeader from '../../layout/components/PageHeader';
+import AppLoader from '../../layout/components/AppLoader';
+import { Tree } from 'primereact/tree';
+import TaskService  from './../../services/task.service';
+import ScheduleService from './../../services/schedule.service';
+import ProjectService from './../../services/project.service';
+
+export class FindObjectResult extends Component{
+    constructor(props){
+        super(props);
+        this.state = {
+            objNodes: [],
+            expandedKeys: {},
+            isLoading: true
+        };
+        this.schedulingSetList= {};
+        this.projectsList= {};
+        this.data= {};
+        this.expandAll = this.expandAll.bind(this);
+        this.expandNode = this.expandNode.bind(this);
+    }
+
+    
+    componentDidUpdate(prevProps, prevState) {
+        const objectType = this.props.match.params.type;
+        const objectId = this.props.match.params.id;
+        const prevObjectType = prevProps.match.params.type;
+        const prevObjectId = prevProps.match.params.id;
+        if(objectType !== prevObjectType || objectId !== prevObjectId){
+            this.findObject();
+        }
+    }
+
+    componentDidMount(){
+        this.findObject();
+    }
+
+    /**
+     * Find Object based in search id
+     */
+    async findObject(){
+        let objNodes = [];
+        this.setState({objNodes: objNodes, isLoading: true});
+        const objectType = this.props.match.params.type;//(this.props.location.state && this.props.location.state.objectType)?this.props.location.state.objectType:'';
+        const objectid = this.props.match.params.id;
+        if (objectType === 'subtask') {
+            objNodes = await this.findSubTask(objectid);
+        }   
+        else if (objectType === 'taskdraft') {
+            objNodes = await this.findTask('draft', objectid);
+        }   
+        else if (objectType === 'taskblueprint') {
+            objNodes = await this.findTask('blueprint', objectid);
+        }   
+        else if (objectType === 'sublueprint') {
+            objNodes = await this.findSchedulingUnit('blueprint', objectid);
+        }   
+        else if (objectType === 'sudraft') {
+            objNodes = await this.findSchedulingUnit('draft', objectid);
+        }   
+        else if (objectType === 'project') {
+            objNodes = await this.findProject(objectid);
+        }
+        this.setState({objNodes: objNodes, isLoading: false});
+        this.expandAll();
+    }
+
+    /**
+     * Find SubTask for given id
+     * @param {*} id 
+     * @returns 
+     */
+    async findSubTask(id){
+        const subtaskDetails  = await TaskService.getSubtaskDetails(id);
+        if (subtaskDetails) {
+            let subtask = {};
+            subtask['key'] = 'subtask'+subtaskDetails.id;
+            subtask['label'] = <> SubTask ({subtaskDetails.id}) 
+                                {/*  -- View page not available yet --
+                                <span className="find-obj-tree-view"><a href="" target='_blank'>View</a></span> */}
+                                <span className="find-obj-tree-view"> <a href={subtaskDetails.url} target='_blank' 
+                                title=" View SubTask API"><i className="fa fa-link" /></a></span></>;
+            subtask['icon'] = 'fas fa-tasks';
+            subtask['children'] = await this.findTask('blueprint', subtaskDetails.task_blueprint_id);
+            return [subtask];
+        }
+        return '';
+    }
+
+    /**
+     * Find Task details for given id
+     * @param {*} taskType 
+     * @param {*} id 
+     * @returns 
+     */
+    async findTask(taskType, id){
+        const taskDetails  = await TaskService.getTask(taskType, id);
+        if (taskDetails) {
+            let task = {};
+            task['key'] = 'task'+taskDetails.id;
+            task['label'] = <> Task ({taskDetails.id}) 
+                                <span className="find-obj-tree-view">
+                                    <a href={`/task/view/${taskType}/${taskDetails.id}`} target='_blank' title=" View Task Details">
+                                            <i className="fa fa-eye" />
+                                    </a>
+                                </span> 
+                                <span> <a href={taskDetails.url} target='_blank' title=" View Task API"><i className="fa fa-link" /></a></span></>;
+            task['icon'] = 'fa fa-tasks';
+            if (taskType === 'blueprint') {
+                task['children'] = await this.findSchedulingUnit('blueprint', taskDetails.scheduling_unit_blueprint_id);
+            }   else {
+                task['children'] = await this.findSchedulingUnit('draft', taskDetails.scheduling_unit_draft_id);
+            }
+            return [task];
+        }
+        return '';
+    }
+
+    /**
+     * Find Scheduling Unit for given id
+     * @param {*} suType 
+     * @param {*} id 
+     * @returns 
+     */
+    async findSchedulingUnit(suType, id){
+        let suDetails = null;
+        if (suType === 'blueprint') {
+            suDetails = await ScheduleService.getSchedulingUnitBlueprintById (id);
+        }   else {
+            suDetails = await ScheduleService.getSchedulingUnitDraftById(id);
+        }
+        if (suDetails) {
+            let schedulingUnit = {};
+            schedulingUnit['key'] = 'su'+suDetails.id;
+            schedulingUnit['label'] = <> Scheduling Unit ({suDetails.id}) 
+                                 <span className="find-obj-tree-view"><a href={`/schedulingunit/view/${suType}/${suDetails.id}`} 
+                                    target='_blank' title=" View Scheduling Unit Details"><i className="fa fa-eye" /></a> </span>
+                                <span><a href={suDetails.url} target='_blank' title=" View Scheduling Unit API" >
+                                    <i className="fa fa-link" /></a></span></>;
+            schedulingUnit['icon'] = 'pi pi-fw pi-calendar';
+            schedulingUnit['children'] = await this.findSchedulingSetBySUId(suDetails);
+           return [schedulingUnit];
+        }
+        return '';
+    }
+
+    /**
+     * Find project for given SU id 
+     * @param {*} suId 
+     */
+    async findSchedulingSetBySUId(suDetails) {
+        const suSetDetails = suDetails.scheduling_set_object;
+        if (suSetDetails) {
+            let suSet = {};
+            suSet['key'] = 'suset'+suSetDetails.id;
+            suSet['label'] = <> Scheduling Set ({suSetDetails.id})
+                                {/*  -- View page not available yet --
+                                <span className="find-obj-tree-view"><a href="" 
+                                target='_blank' title='View Project details'><i className="fa fa-eye" /></a></span> */}
+                                <span className="find-obj-tree-view">
+                                    <a href={suSetDetails.url} target='_blank' title='View Scheduling Set API'><i className="fa fa-link" /></a></span></>;
+            suSet['icon'] = 'fa fa-table';
+            suSet['children'] = await this.findProject(suSetDetails.project_id);
+            return [suSet];
+        }
+        return '';
+    }
+
+    /**
+     * Find project details for given id
+     * @param {*} id 
+     * @returns 
+     */
+    async findProject(id){
+        const projectDetails = await ProjectService.getProjectDetails(id);
+        if (projectDetails) {
+            let project = {};
+            project['key'] = projectDetails.name;
+            project['label'] = <> Project ({projectDetails.name})
+                                <span className="find-obj-tree-view"><a href={`/project/view/${projectDetails.name}`} 
+                                target='_blank' title='View Project details'><i className="fa fa-eye" /></a></span>
+                                <span><a href={projectDetails.url} target='_blank' title='View Project API'><i className="fa fa-link" /></a></span></>;
+            project['icon'] = 'fab fa-fw fa-wpexplorer';
+            return [project];
+        }
+        return '';
+    }
+
+
+    expandNode(node, expandedKeys) {
+        if (node.children && node.children.length) {
+            expandedKeys[node.key] = true;
+
+            for (let child of node.children) {
+                this.expandNode(child, expandedKeys);
+            }
+        }
+    }
+
+    expandAll() {
+        let expandedKeys = {};
+        for (let node of this.state.objNodes) {
+            this.expandNode(node, expandedKeys);
+        }
+        this.setState({expandedKeys: expandedKeys });
+    }
+
+    render(){
+        return(
+            <>
+               <PageHeader location={this.props.location} title={'Search Result'} 
+                    actions={[]}
+                />
+                { this.state.isLoading ? <AppLoader /> :
+                <>
+                    {this.state.objNodes.length > 0 &&
+                        <>
+                            <Tree value={this.state.objNodes} selectionMode="multiple" expandedKeys={this.state.expandedKeys} 
+                                style={{width: 'auto'}} onToggle={e => this.setState({expandedKeys: e.value})} />
+                        </>
+                    }
+                    {this.state.objNodes.length === 0 &&
+                        <> No Object found ! </>
+                    }
+                </>
+                }
+            </>
+        )
+    } 
+}
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Search/index.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Search/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..fcfd0526ca2aec256d95352823d62bab13b9e8a5
--- /dev/null
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Search/index.js
@@ -0,0 +1,3 @@
+import {FindObjectResult} from './find.object.result';
+
+export {FindObjectResult} ;
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/index.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/index.js
index 91955b294875ad02e7bba6314ccadeac920920f1..8af02d3feb05672ec8893e7145f0931b4bec2e85 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/index.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/index.js
@@ -1,5 +1,6 @@
 import {TaskEdit} from './edit';
 import {TaskView} from './view';
 import {DataProduct} from './dataproduct';
+import { TaskList } from './list';
 
-export {TaskEdit, TaskView, DataProduct} ;
+export {TaskEdit, TaskView, DataProduct,TaskList} ;
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/list.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/list.js
new file mode 100644
index 0000000000000000000000000000000000000000..5bdef19b88263dc4fab8d695fc6ae02f9d2f7f49
--- /dev/null
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/list.js
@@ -0,0 +1,384 @@
+import React, {Component} from 'react';
+import {Redirect} from 'react-router-dom'
+import moment from 'moment';
+import { Dialog } from 'primereact/dialog';
+import { DataTable } from 'primereact/datatable';
+import { Column } from 'primereact/column';
+import _ from 'lodash';
+import TaskService from '../../services/task.service';
+import AppLoader from '../../layout/components/AppLoader';
+import PageHeader from '../../layout/components/PageHeader';
+import ViewTable from '../../components/ViewTable';
+import UIConstants from '../../utils/ui.constants';
+import TaskStatusLogs from './state_logs';
+import { appGrowl } from '../../layout/components/AppGrowl';
+import { CustomDialog } from '../../layout/components/CustomDialog';
+import ScheduleService from '../../services/schedule.service';
+import UnitConverter from '../../utils/unit.converter';
+
+export class TaskList extends Component {
+    constructor(props) {
+        super(props);
+        this.state = {
+            isLoading: true,
+            tasks: [],
+            paths: [{
+                "View": "/task",
+            }],
+            columnOrders: [
+                "Status Logs",
+                 "Status",
+                 "Type",
+                 "Scheduling Unit ID",
+                 "Scheduling Unit Name",
+                 "ID",
+                 "Control ID",
+                 "Name",
+                 "Description",
+                 "Start Time",
+                 "End Time",
+                 "Duration (HH:mm:ss)",
+                 "Relative Start Time (HH:mm:ss)",
+                 "Relative End Time (HH:mm:ss)",
+                 "#Dataproducts",
+                 "size",
+                 "dataSizeOnDisk",
+                 "subtaskContent",
+                 "tags",
+                 "blueprint_draft",
+                 "url",
+                 "Cancelled",
+                 "Created at",
+                 "Updated at"
+             ],
+            dialog: {},
+            defaultcolumns: [ {
+                status_logs: "Status Logs",
+                status:{
+                    name:"Status",
+                    filter: "select"
+                },
+                tasktype:{
+                    name:"Type",
+                    filter:"select"
+                },
+                schedulingUnitId: "Scheduling Unit ID",
+                schedulingUnitName: "Scheduling Unit Name",
+                id: "ID",
+                subTaskID: 'Control ID',
+                name:"Name",
+                description:"Description",
+                start_time:{
+                    name:"Start Time",
+                    filter: "date",
+                    format:UIConstants.CALENDAR_DATETIME_FORMAT
+                },
+                stop_time:{
+                    name:"End Time",
+                    filter: "date",
+                    format:UIConstants.CALENDAR_DATETIME_FORMAT
+                },
+                duration:"Duration (HH:mm:ss)",
+                relative_start_time:"Relative Start Time (HH:mm:ss)",
+                relative_stop_time:"Relative End Time (HH:mm:ss)",
+                noOfOutputProducts: "#Dataproducts",
+                do_cancel:{
+                    name: "Cancelled",
+                    filter: "switch"
+                },
+            }],
+            optionalcolumns:  [{
+                size: "Data size",
+                dataSizeOnDisk: "Data size on Disk",
+                subtaskContent: "Subtask Content",
+                tags:"Tags",
+                blueprint_draft:"BluePrint / Task Draft link",
+                url:"API URL",
+                created_at:{
+                    name: "Created at",
+                    filter: "date",
+                    format:UIConstants.CALENDAR_DATETIME_FORMAT
+                },
+                updated_at:{
+                    name: "Updated at",
+                    filter: "date",
+                    format:UIConstants.CALENDAR_DATETIME_FORMAT
+                },
+                actionpath:"actionpath"
+            }],
+            columnclassname: [{
+                "Status Logs": "filter-input-0",
+                "Type":"filter-input-75",
+                "Scheduling Unit ID": "filter-input-50",
+                "Scheduling Unit Name": "filter-input-100",
+                "ID":"filter-input-50",
+                "Control ID":"filter-input-75",
+                "Cancelled":"filter-input-50",
+                "Duration (HH:mm:ss)":"filter-input-75",
+                "Template ID":"filter-input-50",
+                // "BluePrint / Task Draft link": "filter-input-100",
+                "Relative Start Time (HH:mm:ss)": "filter-input-75",
+                "Relative End Time (HH:mm:ss)": "filter-input-75",
+                "Status":"filter-input-100",
+                "#Dataproducts":"filter-input-75",
+                "Data size":"filter-input-50",
+                "Data size on Disk":"filter-input-50",
+                "Subtask Content":"filter-input-75",
+                "BluePrint / Task Draft link":"filter-input-50",
+            }]
+        };
+        this.selectedRows = [];
+        this.subtaskTemplates = [];
+        this.confirmDeleteTasks = this.confirmDeleteTasks.bind(this);
+        this.onRowSelection = this.onRowSelection.bind(this);
+        this.deleteTasks = this.deleteTasks.bind(this);
+        this.closeDialog = this.closeDialog.bind(this);
+        this.getTaskDialogContent = this.getTaskDialogContent.bind(this);
+    }
+
+    subtaskComponent = (task)=> {
+        return (
+            <button className="p-link" onClick={(e) => {this.setState({showStatusLogs: true, task: task})}}>
+                <i className="fa fa-history"></i>
+            </button>
+        );
+    };
+
+
+    /**
+     * Formatting the task_blueprints in blueprint view to pass to the ViewTable component
+     * @param {Object} schedulingUnit - scheduling_unit_blueprint object from extended API call loaded with tasks(blueprint) along with their template and subtasks
+     */
+     getFormattedTaskBlueprints(schedulingUnit) {
+        let taskBlueprintsList = [];
+        for(const taskBlueprint of schedulingUnit.task_blueprints) {
+            taskBlueprint['status_logs'] = this.subtaskComponent(taskBlueprint);
+            taskBlueprint['tasktype'] = 'Blueprint';
+            taskBlueprint['actionpath'] = '/task/view/blueprint/'+taskBlueprint['id'];
+            taskBlueprint['blueprint_draft'] = taskBlueprint['draft'];
+            taskBlueprint['relative_start_time'] = 0;
+            taskBlueprint['relative_stop_time'] = 0;
+            taskBlueprint.duration = moment.utc((taskBlueprint.duration || 0)*1000).format(UIConstants.CALENDAR_TIME_FORMAT);
+            taskBlueprint.template = taskBlueprint.specifications_template; 
+            taskBlueprint.schedulingUnitName = schedulingUnit.name;
+            for (const subtask of taskBlueprint.subtasks) {
+                subtask.subTaskTemplate = _.find(this.subtaskTemplates, ['id', subtask.specifications_template_id]);
+            }
+            taskBlueprint.schedulingUnitId = taskBlueprint.scheduling_unit_blueprint_id;
+            taskBlueprint.subTasks = taskBlueprint.subtasks;           
+            taskBlueprintsList.push(taskBlueprint);
+        }
+        return taskBlueprintsList;
+    }
+
+    /**
+     * Formatting the task_drafts and task_blueprints in draft view to pass to the ViewTable component
+     * @param {Object} schedulingUnit - scheduling_unit_draft object from extended API call loaded with tasks(draft & blueprint) along with their template and subtasks
+     */
+     getFormattedTaskDrafts(schedulingUnit) {
+        let scheduletasklist=[];
+        // Common keys for Task and Blueprint
+        let commonkeys = ['id','created_at','description','name','tags','updated_at','url','do_cancel','relative_start_time','relative_stop_time','start_time','stop_time','duration','status'];
+        for(const task of schedulingUnit.task_drafts){
+            let scheduletask = {};
+            scheduletask['tasktype'] = 'Draft';
+            scheduletask['actionpath'] = '/task/view/draft/'+task['id'];
+            scheduletask['blueprint_draft'] = _.map(task['task_blueprints'], 'url');
+            scheduletask['status'] = task['status'];
+
+            //fetch task draft details
+            for(const key of commonkeys){
+                scheduletask[key] = task[key];
+            }
+            scheduletask['specifications_doc'] = task['specifications_doc'];
+            scheduletask.duration = moment.utc((scheduletask.duration || 0)*1000).format(UIConstants.CALENDAR_TIME_FORMAT); 
+            scheduletask.relative_start_time = moment.utc(scheduletask.relative_start_time*1000).format(UIConstants.CALENDAR_TIME_FORMAT); 
+            scheduletask.relative_stop_time = moment.utc(scheduletask.relative_stop_time*1000).format(UIConstants.CALENDAR_TIME_FORMAT); 
+            scheduletask.template = task.specifications_template;
+            scheduletask.type_value = task.specifications_template.type_value;
+            scheduletask.produced_by = task.produced_by;
+            scheduletask.produced_by_ids = task.produced_by_ids;
+            scheduletask.schedulingUnitId = task.scheduling_unit_draft_id;
+            scheduletask.schedulingUnitName = schedulingUnit.name;
+            //Add Task Draft details to array
+            scheduletasklist.push(scheduletask);
+        }
+        return scheduletasklist;
+    }
+
+    async formatDataProduct(tasks) {
+        await Promise.all(tasks.map(async task => {
+            task.status_logs = task.tasktype === "Blueprint"?this.subtaskComponent(task):"";
+            //Displaying SubTask ID of the 'control' Task
+            const subTaskIds = task.subTasks?task.subTasks.filter(sTask => sTask.subTaskTemplate.name.indexOf('control') >= 0):[];
+            const promise = [];
+            subTaskIds.map(subTask => promise.push(ScheduleService.getSubtaskOutputDataproduct(subTask.id)));
+            const dataProducts = promise.length > 0? await Promise.all(promise):[];
+            task.dataProducts = [];
+            task.size = 0;
+            task.dataSizeOnDisk = 0;
+            task.noOfOutputProducts = 0;
+            task.canSelect = task.tasktype.toLowerCase() === 'blueprint' ? true:(task.tasktype.toLowerCase() === 'draft' && task.blueprint_draft.length === 0)?true:false;
+            if (dataProducts.length && dataProducts[0].length) {
+                task.dataProducts = dataProducts[0];
+                task.noOfOutputProducts = dataProducts[0].length;
+                task.size = _.sumBy(dataProducts[0], 'size');
+                task.dataSizeOnDisk = _.sumBy(dataProducts[0], function(product) { return product.deletedSince?0:product.size});
+                task.size = UnitConverter.getUIResourceUnit('bytes', (task.size));
+                task.dataSizeOnDisk = UnitConverter.getUIResourceUnit('bytes', (task.dataSizeOnDisk));
+            }
+            task.subTaskID = subTaskIds.length ? subTaskIds[0].id : ''; 
+            return task;
+        }));
+        return tasks;
+    }
+
+
+    async componentDidMount() {
+        this.subtaskTemplates = await TaskService.getSubtaskTemplates()
+        const promises = [
+            ScheduleService.getSchedulingUnitsExtended('draft'), 
+            ScheduleService.getSchedulingUnitsExtended('blueprint')
+        ];
+        Promise.all(promises).then(async (responses) => {
+            let allTasks = [];
+            for (const schedulingUnit of responses[0]) {
+                let tasks = schedulingUnit.task_drafts?(await this.getFormattedTaskDrafts(schedulingUnit)):this.getFormattedTaskBlueprints(schedulingUnit);
+                let ingestGroup = tasks.map(task => ({name: task.name, canIngest: task.canIngest, type_value: task.type_value, id: task.id }));
+                ingestGroup = _.groupBy(_.filter(ingestGroup, 'type_value'), 'type_value');
+                tasks = await this.formatDataProduct(tasks);
+                allTasks = [...allTasks, ...tasks];
+            }
+            for (const schedulingUnit of responses[1]) {
+                let tasks = schedulingUnit.task_drafts?(await this.getFormattedTaskDrafts(schedulingUnit)):this.getFormattedTaskBlueprints(schedulingUnit);
+                let ingestGroup = tasks.map(task => ({name: task.name, canIngest: task.canIngest, type_value: task.type_value, id: task.id }));
+                ingestGroup = _.groupBy(_.filter(ingestGroup, 'type_value'), 'type_value');
+                tasks = await this.formatDataProduct(tasks);
+                allTasks = [...allTasks, ...tasks];
+            }
+            this.setState({ tasks: allTasks,  isLoading: false });
+        });
+    }
+
+    /**
+     * Prepare Task(s) details to show on confirmation dialog
+     */
+     getTaskDialogContent() {
+        let selectedTasks = [];
+        for(const obj of this.selectedRows) {
+            selectedTasks.push({id:obj.id, suId: obj.schedulingUnitId, suName: obj.schedulingUnitName, 
+                taskId: obj.id, controlId: obj.subTaskID, taskName: obj.name, status: obj.status});
+        }   
+        return  <>  
+                <DataTable value={selectedTasks} resizableColumns columnResizeMode="expand" className="card" style={{paddingLeft: '0em'}}>
+                    <Column field="suId" header="Scheduling Unit Id"></Column>
+                    <Column field="taskId" header="Task Id"></Column>
+                    <Column field="taskName" header="Task Name"></Column>
+                    <Column field="status" header="Status"></Column>
+                </DataTable>
+        </>
+    }
+
+    confirmDeleteTasks() {
+        if(this.selectedRows.length === 0) {
+            appGrowl.show({severity: 'info', summary: 'Select Row', detail: 'Select Task to delete.'});
+        }   else {
+            let dialog = {};
+            dialog.type = "confirmation";
+            dialog.header= "Confirm to Delete Task(s)";
+            dialog.detail = "Do you want to delete the selected Task(s)?";
+            dialog.content = this.getTaskDialogContent;
+            dialog.actions = [{id: 'yes', title: 'Yes', callback: this.deleteTasks},
+            {id: 'no', title: 'No', callback: this.closeDialog}];
+            dialog.onSubmit = this.deleteTasks;
+            dialog.width = '55vw';
+            dialog.showIcon = false;
+            this.setState({dialog: dialog, dialogVisible: true});
+        }
+    }
+
+    /**
+     * Delete Task(s)
+     */
+    async deleteTasks() {
+        let hasError = false;
+        for(const task of this.selectedRows) {
+            if(!await TaskService.deleteTask(task.tasktype, task.id)) {
+                hasError = true;
+            }
+        }
+        if(hasError){
+            appGrowl.show({severity: 'error', summary: 'error', detail: 'Error while deleting Task(s)'});
+            this.setState({dialogVisible: false});
+        }   else {
+            this.selectedRows = [];
+            this.setState({dialogVisible: false});
+            this.componentDidMount();
+            appGrowl.show({severity: 'success', summary: 'Success', detail: 'Task(s) deleted successfully'});
+        }
+    }
+
+    /**
+     * Callback function to close the dialog prompted.
+     */
+    closeDialog() {
+        this.setState({dialogVisible: false});
+    }
+
+    onRowSelection(selectedRows) {
+        this.selectedRows = selectedRows;
+    }
+
+
+    render() {
+        if (this.state.redirect) {
+            return <Redirect to={ {pathname: this.state.redirect} }></Redirect>
+        }
+
+        return (
+            <React.Fragment>
+                <PageHeader location={this.props.location} title={'Task - List'} />
+                {this.state.isLoading? <AppLoader /> :
+                     <>
+                     <div className="delete-option">
+                        <div >
+                            <span className="p-float-label">
+                                <a href="#" onClick={this.confirmDeleteTasks}  title="Delete selected Task(s)">
+                                    <i class="fa fa-trash" aria-hidden="true" ></i>
+                                </a>
+                            </span>
+                        </div>                           
+                    </div>
+                    <ViewTable 
+                        data={this.state.tasks} 
+                        defaultcolumns={this.state.defaultcolumns}
+                        optionalcolumns={this.state.optionalcolumns}
+                        columnclassname={this.state.columnclassname}
+                        columnOrders={this.state.columnOrders}
+                        defaultSortColumn={this.state.defaultSortColumn}
+                        showaction="true"
+                        keyaccessor="id"
+                        paths={this.state.paths}
+                        unittest={this.state.unittest}
+                        tablename="scheduleunit_task_list"
+                        allowRowSelection={true}
+                        onRowSelection = {this.onRowSelection}
+                    />
+                </>
+                }
+                {this.state.showStatusLogs &&
+                    <Dialog header={`Status change logs - ${this.state.task?this.state.task.name:""}`} 
+                            visible={this.state.showStatusLogs} maximizable maximized={false} position="left" style={{ width: '50vw' }} 
+                            onHide={() => {this.setState({showStatusLogs: false})}}>
+                            <TaskStatusLogs taskId={this.state.task.id}></TaskStatusLogs>
+                    </Dialog>
+                }
+                <CustomDialog type="confirmation" visible={this.state.dialogVisible}
+                    header={this.state.dialog.header} message={this.state.dialog.detail} actions={this.state.dialog.actions}
+                    content={this.state.dialog.content} width={this.state.dialog.width} showIcon={this.state.dialog.showIcon}
+                    onClose={this.closeDialog} onCancel={this.closeDialog} onSubmit={this.state.dialog.onSubmit}/>
+            </React.Fragment>
+        );
+    }
+} 
+ 
\ No newline at end of file
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/view.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/view.js
index f89c15afe62c4ea33919c10b6a7e1de07c01a4e3..8a5fe8ea36ca313089e04a5154f7d7899a37d83b 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/view.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/view.js
@@ -71,12 +71,9 @@ export class TaskView extends Component {
     }
 
     componentDidMount() {
-        // const taskId = this.props.location.state?this.props.location.state.id:this.state.taskId;
-        // let taskType = this.props.location.state?this.props.location.state.type:this.state.taskType;
-        // taskType = taskType?taskType:'draft';
-        let {taskId, taskType} = this.state;
-        taskId = taskId?taskId:this.props.location.state.id;
-        taskType = taskType?taskType:this.props.location.state.type;
+        const taskId = this.props.location.state?this.props.location.state.id:this.state.taskId;
+        let taskType = this.props.location.state && this.props.location.state.type?this.props.location.state.type:this.state.taskType;
+        taskType = taskType?taskType:'draft';
 
         if (taskId && taskType) {
             this.getTaskDetails(taskId, taskType);
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/index.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/index.js
index 2076201f6695b183946734cc9e1aa6a2b26b5ea0..658c2a00acf6f252714630e1c88ad3eec7f8b3d7 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/index.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/index.js
@@ -2,4 +2,5 @@ import {TimelineView} from './view';
 import {WeekTimelineView} from './week.view';
 import { ReservationList} from './reservation.list';
 import { ReservationCreate } from  './reservation.create';
-export {TimelineView, WeekTimelineView, ReservationCreate, ReservationList} ;
+import { ReservationSummary } from  './reservation.summary';
+export {TimelineView, WeekTimelineView, ReservationCreate, ReservationList, ReservationSummary} ;
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/reservation.create.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/reservation.create.js
index e1b884053169d5a05dd9ab001e45af3c7ae0804a..ac7fa0216a2074478fa88d6af869a0233affefa4 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/reservation.create.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/reservation.create.js
@@ -7,7 +7,6 @@ import AppLoader from '../../layout/components/AppLoader';
 import PageHeader from '../../layout/components/PageHeader';
 import UIConstants from '../../utils/ui.constants';
 import Flatpickr from "react-flatpickr";
-import { Calendar } from 'primereact/calendar';
 import { InputMask } from 'primereact/inputmask';
 import { Dropdown } from 'primereact/dropdown';
 import {InputText } from 'primereact/inputtext';
@@ -43,14 +42,13 @@ export class ReservationCreate extends Component {
                 name: '',
                 description: '', 
                 start_time: null,
-                duration: '',
+                stop_time: null,
                 project: (props.match?props.match.params.project:null) || null,
             },
             errors: {},                             // Validation Errors
             validFields: {},                        // For Validation
             validForm: false,                       // To enable Save Button
-            validEditor: false, 
-            durationError: false,
+            validEditor: false
         };
         this.projects = [];                         // All projects to load project dropdown
         this.reservationTemplates = [];
@@ -143,13 +141,6 @@ export class ReservationCreate extends Component {
      * @param {any} value 
      */
     setParams(key, value, type) {
-        if(key === 'duration' && !this.validateDuration( value)) {
-            this.setState({
-                durationError: true,
-                isDirty: true
-            })
-            return;
-        }
         let reservation = this.state.reservation;
         switch(type) {
             case 'NUMBER': {
@@ -161,23 +152,9 @@ export class ReservationCreate extends Component {
                 break;
             }
         }
-        this.setState({reservation: reservation, validForm: this.validateForm(key), durationError: false, isDirty: true});
+        this.setState({reservation: reservation, validForm: this.validateForm(key), isDirty: true});
     }
      
-    /**
-     * Validate Duration, it allows max 99:59:59
-     * @param {*} duration 
-     */
-    validateDuration(duration) {
-        const splitOutput = duration.split(':');
-        if (splitOutput.length < 3) {
-            return false;
-        } else if (parseInt(splitOutput[1])>59 || parseInt(splitOutput[2])>59) {
-            return false;
-        }
-        return true;
-    }
-
     /**
      * Validation function to validate the form or field based on the form rules.
      * If no argument passed for fieldName, validates all fields in the form.
@@ -219,10 +196,37 @@ export class ReservationCreate extends Component {
         this.setState({errors: errors, validFields: validFields});
         if (Object.keys(validFields).length === Object.keys(this.formRules).length) {
             validForm = true;
+            delete errors['start_time'];
+            delete errors['stop_time'];
+        }
+        if (!this.validateDates(this.state.reservation.start_time, this.state.reservation.stop_time)) {
+            validForm = false;
+            if (!fieldName || fieldName === 'start_time') {
+                errors['start_time'] = "From Date cannot be same or after To Date";
+                delete errors['stop_time'];
+            }
+            if (!fieldName || fieldName === 'stop_time') {
+                errors['stop_time'] = "To Date cannot be same or before From Date";
+                delete errors['start_time'];
+            }
+            this.setState({errors: errors});
         }
         return validForm;
     }
 
+    /**
+     * Function to validate if stop_time is always later than start_time if exists.
+     * @param {Date} fromDate 
+     * @param {Date} toDate 
+     * @returns boolean
+     */
+    validateDates(fromDate, toDate) {
+        if (fromDate && toDate && moment(toDate).isSameOrBefore(moment(fromDate))) {
+            return false;
+        }
+        return true;
+    }
+
     setEditorOutput(jsonOutput, errors) {
         this.paramsOutput = jsonOutput;
         this.validEditor = errors.length === 0;
@@ -242,7 +246,7 @@ export class ReservationCreate extends Component {
         let reservation = this.state.reservation;
         let project = this.projects.find(project => project.name === reservation.project);
         reservation['start_time'] = moment(reservation['start_time']).format(UIConstants.CALENDAR_DATETIME_FORMAT);
-        reservation['duration'] = ( reservation['duration'] === ''? null: UnitService.getHHmmssToSecs(reservation['duration']));
+        reservation['stop_time'] = reservation['stop_time']?moment(reservation['stop_time']).format(UIConstants.CALENDAR_DATETIME_FORMAT):reservation['stop_time'];
         reservation['project']=  project ? project.url: null;
         reservation['specifications_template']= this.reservationTemplates[0].url;
         reservation['specifications_doc']= this.paramsOutput;
@@ -263,7 +267,7 @@ export class ReservationCreate extends Component {
             name: '',
             description: '', 
             start_time: '',
-            duration: '',
+            stop_time: '',
             project: '',
         }
         this.setState({
@@ -360,13 +364,14 @@ export class ReservationCreate extends Component {
                                 </div>
                             </div>
                             <div className="p-field p-grid">
-                                    <label htmlFor="reservationName" className="col-lg-2 col-md-2 col-sm-12">From Date <span style={{color:'red'}}>*</span></label>
+                                    <label className="col-lg-2 col-md-2 col-sm-12">From Date <span style={{color:'red'}}>*</span></label>
                                     <div className="col-lg-3 col-md-3 col-sm-12">
                                         <Flatpickr data-enable-time data-input options={{
                                                     "inlineHideInput": true,
                                                     "wrap": true,
                                                     "enableSeconds": true,
                                                     "time_24hr": true,
+                                                    "minuteIncrement": 1,
                                                     "allowInput": true,
                                                     "defaultDate": this.state.systemTime.format(UIConstants.CALENDAR_DEFAULTDATE_FORMAT),
                                                     "defaultHour": this.state.systemTime.hours(),
@@ -387,21 +392,33 @@ export class ReservationCreate extends Component {
                                     </div>
                                     <div className="col-lg-1 col-md-1 col-sm-12"></div>
                              
-                                    <label htmlFor="duration" className="col-lg-2 col-md-2 col-sm-12">Duration </label>
-                                    <div className="col-lg-3 col-md-3 col-sm-12" data-testid="duration" >
-                                        <InputMask 
-                                            value={this.state.reservation.duration} 
-                                            mask="99:99:99" 
-                                            placeholder="HH:mm:ss" 
-                                            tooltip="Duration of this reservation. If it is empty, then this reservation is indefinite."
-                                            tooltipOptions={this.tooltipOptions}
-                                            onChange= {e => this.setParams('duration',e.value)}
-                                            ref={input =>{this.input = input}}
-                                            />
-                                        <label className="error">
-                                            {this.state.durationError ? 'Invalid duration, Maximum:99:59:59.' : ""}
+                                    <label className="col-lg-2 col-md-2 col-sm-12">To Date</label>
+                                    <div className="col-lg-3 col-md-3 col-sm-12">
+                                        <Flatpickr data-enable-time data-input options={{
+                                                    "inlineHideInput": true,
+                                                    "wrap": true,
+                                                    "enableSeconds": true,
+                                                    "time_24hr": true,
+                                                    "minuteIncrement": 1,
+                                                    "allowInput": true,
+                                                    "minDate": this.state.reservation.start_time?this.state.reservation.start_time.toDate:'',
+                                                    "defaultDate": this.state.systemTime.format(UIConstants.CALENDAR_DEFAULTDATE_FORMAT),
+                                                    "defaultHour": this.state.systemTime.hours(),
+                                                    "defaultMinute": this.state.systemTime.minutes()
+                                                    }}
+                                                    title="End of this reservation. If empty, then this reservation is indefinite."
+                                                    value={this.state.reservation.stop_time}
+                                                    onChange= {value => {this.setParams('stop_time', value[0]?value[0]:this.state.reservation.stop_time);
+                                                                            this.setReservationParams('stop_time', value[0]?value[0]:this.state.reservation.stop_time)}} >
+                                            <input type="text" data-input className={`p-inputtext p-component ${this.state.errors.stop_time && this.state.touched.stop_time?'input-error':''}`} />
+                                            <i className="fa fa-calendar" data-toggle style={{position: "absolute", marginLeft: '-25px', marginTop:'5px', cursor: 'pointer'}} ></i>
+                                            <i className="fa fa-times" style={{position: "absolute", marginLeft: '-50px', marginTop:'5px', cursor: 'pointer'}} 
+                                                onClick={e => {this.setParams('stop_time', ''); this.setReservationParams('stop_time', '')}}></i>
+                                        </Flatpickr>
+                                        <label className={this.state.errors.stop_time && this.state.touched.stop_time?"error":"info"}>
+                                            {this.state.errors.stop_time && this.state.touched.stop_time ? this.state.errors.stop_time : ""}
                                         </label>
-                                    </div>     
+                                    </div>
                                 </div>
 
                                 <div className="p-field p-grid">
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/reservation.list.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/reservation.list.js
index dd776d470c2d3a496d7a3f355cad38d47f75dd28..98ab06258512115f9abd678c19759de163f9c106 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/reservation.list.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/reservation.list.js
@@ -30,7 +30,7 @@ export class ReservationList extends Component{
                     filter: "fromdatetime",
                     format:UIConstants.CALENDAR_DATETIME_FORMAT
                 },
-                end_time: {
+                stop_time: {
                     name: "End Time",
                     filter: "todatetime",
                     format:UIConstants.CALENDAR_DATETIME_FORMAT
@@ -118,19 +118,17 @@ export class ReservationList extends Component{
                 reservation = this.mergeResourceWithReservation( reservation, response.specifications_doc.effects );
                 reservation = this.mergeResourceWithReservation( reservation, response.specifications_doc.schedulability );
                 if (response.specifications_doc.resources.stations ) {
-                    reservation['stations'] = response.specifications_doc.resources.stations.join();
+                    reservation['stations'] = response.specifications_doc.resources.stations.join(', ');
                 } else {
                     reservation['stations'] = '';
                 }
                 if(reservation.duration === null || reservation.duration === ''){
                     reservation.duration = 'Unknown';
-                    reservation['end_time']= 'Unknown';
+                    reservation['stop_time']= 'Unknown';
                 } else {
                     let duration = reservation.duration;
                     reservation.duration = UnitService.getSecsToHHmmss(reservation.duration);
-                    let endDate = moment(reservation.start_time);
-                    endDate = moment(endDate).add(duration, 's');
-                    reservation['end_time']= moment(endDate).format(UIConstants.CALENDAR_DATETIME_FORMAT);
+                    reservation['stop_time']= moment(reservation['stop_time']).format(UIConstants.CALENDAR_DATETIME_FORMAT);
                 }
                 reservation['start_time']= moment(reservation['start_time']).format(UIConstants.CALENDAR_DATETIME_FORMAT);
                 this.reservations.push(reservation);
@@ -177,9 +175,9 @@ export class ReservationList extends Component{
                     let cycle_End_time = moment.utc(moment(cycle['stop']).format("YYYY-MM-DD"));  
                     this.state.reservationsList.forEach( reservation => {
                         let res_Start_time = moment.utc(moment(reservation['start_time']).format("YYYY-MM-DD"));  
-                        let res_End_time = moment.utc(moment(reservation['end_time']).format("YYYY-MM-DD"));  
+                        let res_End_time = moment.utc(moment(reservation['stop_time']).format("YYYY-MM-DD"));  
                         if (cycle_Start_time.isSameOrBefore(res_Start_time) && cycle_End_time.isSameOrAfter(res_Start_time)) {
-                            if ( reservation['end_time'] === 'Unknown'|| cycle_End_time.isSameOrAfter(res_End_time)) {
+                            if ( reservation['stop_time'] === 'Unknown'|| cycle_End_time.isSameOrAfter(res_End_time)) {
                                 const tmpList = _.filter(reservationList, function(o) { return o.id === reservation.id });
                                 if( tmpList.length === 0) {
                                     reservationList.push(reservation);
@@ -216,7 +214,7 @@ export class ReservationList extends Component{
             await this.state.reservationsList.forEach( reservation => {
                 let res_Start_time =  moment.utc(moment(reservation['start_time'])).valueOf();
                 let res_End_time = 'Unknown';
-                if(reservation['end_time'] === 'Unknown') {
+                if(reservation['stop_time'] === 'Unknown') {
                     if(res_Start_time <= fEndTime){
                         const tmpList = _.filter(reservationList, function(o) { return o.id === reservation.id });
                         if( tmpList.length === 0) {
@@ -225,7 +223,7 @@ export class ReservationList extends Component{
                     }
                 } 
                 else {
-                    res_End_time = moment.utc(moment(reservation['end_time'])).valueOf();
+                    res_End_time = moment.utc(moment(reservation['stop_time'])).valueOf();
                     if(res_Start_time <= fStartTime && res_End_time >= fStartTime) {
                         const tmpList = _.filter(reservationList, function(o) { return o.id === reservation.id });
                         if( tmpList.length === 0) {
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/reservation.summary.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/reservation.summary.js
new file mode 100644
index 0000000000000000000000000000000000000000..50a80c71b0af29f2090e8f00ab6cac1c057b54f3
--- /dev/null
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/reservation.summary.js
@@ -0,0 +1,139 @@
+import React, {Component} from 'react';
+import { Link } from 'react-router-dom/cjs/react-router-dom.min';
+import moment from 'moment';
+import _ from 'lodash';
+import { JsonToTable } from "react-json-to-table";
+import UIConstants from '../../utils/ui.constants';
+import UnitConverter from '../../utils/unit.converter';
+
+/**
+ * Component to view summary of the Reservation
+ */
+export class ReservationSummary extends Component {
+
+    constructor(props) {
+        super(props);
+        this.closeSUDets = this.closeSUDets.bind(this);
+    }
+
+    componentDidMount() {}
+
+    /**
+     * Function to close the summary panel and call parent callback function to close.
+     */
+    closeSUDets() {
+        if(this.props.closeCallback) {
+            this.props.closeCallback();
+        }
+    }
+
+    /**
+     * Function to order or format all specifications to readable values
+     * @param {Object} specifications 
+     */
+    getOrderedSpecifications(specifications) {
+        for (const specKey of _.keys(specifications)) {
+            let specification = this.getFormattedSpecification(specifications[specKey]);
+            specifications[specKey] = specification;
+        }
+        return specifications;
+    }
+
+    /**
+     * Function to format date, boolean, array object to readable values
+     * @param {Object} specification 
+     */
+    getFormattedSpecification(specification) {
+        if (specification !== null) {
+            const objectType = typeof specification;
+            switch(objectType) {
+                case "string": {
+                    try {
+                        const dateValue = moment.utc(specification);
+                        if (dateValue.isValid()) {
+                            specification = dateValue.format(UIConstants.CALENDAR_DATETIME_FORMAT);
+                        }
+                    } catch (error) {}
+                    break;
+                }
+                case "boolean": {
+                    specification = specification?'True':'False';
+                    break;
+                }
+                case "object": {
+                    if (Array.isArray(specification)) {
+                        let newArray = [], isStringArray = false;
+                        for (let arrayObj of specification) {
+                            arrayObj = this.getFormattedSpecification(arrayObj);
+                            if (arrayObj) {
+                                if ((typeof arrayObj) === "string") {
+                                    isStringArray = true;
+                                }
+                                newArray.push(arrayObj);
+                            }
+                        }
+                        specification = newArray.length > 0?(isStringArray?newArray.join(", "):newArray):null;
+                    }   else {
+                        let newObject = {};
+                        let keys = _.keys(specification);
+                        for (const objectKey of _.keys(specification)) {
+                            let object = this.getFormattedSpecification(specification[objectKey]);
+                            if (object) {
+                                newObject[objectKey.replace(/_/g, ' ')] = object;
+                            }
+                        }
+                        specification = (!_.isEmpty(newObject))? newObject:null;
+                    }
+                    break;
+                }
+                default: {}
+            }
+        }
+        return specification;
+    }
+
+    render() {
+        const reservation = this.props.reservation;
+        let specifications = reservation?_.cloneDeep(reservation.specifications_doc):null;
+        if (specifications) {
+            // Remove $schema variable
+            delete specifications['$schema'];
+        }
+        return (
+            <React.Fragment>
+            { reservation &&
+                <div className="p-grid timeline-details-pane" style={{marginTop: '10px'}}>
+                    <h6 className="col-lg-10 col-sm-10">Reservation Details</h6>
+                    {/* TODO: Enable the link once Reservation view page is created */}
+                    {/* <Link to={`/su/timeline/reservation/view/${reservation.id}`} title="View Full Details" ><i className="fa fa-eye"></i></Link> */}
+                    <i className="fa fa-eye" style={{color: 'grey'}}></i>
+                    <Link to={this.props.location?this.props.location.pathname:"/su/timelineview"} onClick={this.closeSUDets} title="Close Details"><i className="fa fa-times"></i></Link>
+                    <div className="col-4"><label>Name:</label></div>
+                    <div className="col-8">{reservation.name}</div>
+                    <div className="col-4"><label>Description:</label></div>
+                    <div className="col-8">{reservation.description}</div>
+                    <div className="col-4"><label>Project:</label></div>
+                    <div className="col-8">{reservation.project}</div>
+                    <div className="col-4"><label>Start Time:</label></div>
+                    <div className="col-8">{moment.utc(reservation.start_time).format(UIConstants.CALENDAR_DATETIME_FORMAT)}</div>
+                    <div className="col-4"><label>Stop Time:</label></div>
+                    <div className="col-8">{moment.utc(reservation.stop_time).format(UIConstants.CALENDAR_DATETIME_FORMAT)}</div>
+                    <div className="col-4"><label>Duration (HH:mm:ss):</label></div>
+                    <div className="col-8">{UnitConverter.getSecsToHHmmss(reservation.duration)}</div>
+                    {/* Reservation parameters Display in table format */}
+                    {reservation.specifications_doc &&
+                        <>
+                        <div className="col-12 constraints-summary">
+                            <label>Parameters:</label>
+                            <JsonToTable json={this.getOrderedSpecifications(specifications)} />
+                        </div>
+                        </>
+                    }
+                </div>
+            }
+            </React.Fragment>
+        );
+    }
+}
+
+export default ReservationSummary;
\ No newline at end of file
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 56437953e4ee0ed1bd91c69fda2fd9512bb7f703..7c8436aeacf4e17fa5b73fef1a7c73b81b7eb308 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/view.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/view.js
@@ -22,6 +22,7 @@ import TaskService from '../../services/task.service';
 import UnitConverter from '../../utils/unit.converter';
 import Validator from '../../utils/validator';
 import SchedulingUnitSummary from '../Scheduling/summary';
+import ReservationSummary from './reservation.summary';
 import { Dropdown } from 'primereact/dropdown';
 import { OverlayPanel } from 'primereact/overlaypanel';
 import { RadioButton } from 'primereact/radiobutton';
@@ -88,6 +89,7 @@ export class TimelineView extends Component {
         this.onItemMouseOver = this.onItemMouseOver.bind(this);
         this.onItemMouseOut = this.onItemMouseOut.bind(this);
         this.showSUSummary = this.showSUSummary.bind(this);
+        this.showReservationSummary = this.showReservationSummary.bind(this);
         this.showTaskSummary = this.showTaskSummary.bind(this);
         this.closeSUDets = this.closeSUDets.bind(this);
         this.dateRangeCallback = this.dateRangeCallback.bind(this);
@@ -295,6 +297,8 @@ export class TimelineView extends Component {
     onItemClick(item) {
         if (item.type === "SCHEDULE") { 
             this.showSUSummary(item);
+        }   else if (item.type === "RESERVATION") {
+            this.showReservationSummary(item);
         }   else {
             this.showTaskSummary(item);
         }
@@ -349,6 +353,14 @@ export class TimelineView extends Component {
         }
     }
 
+    /**
+     * To load and show Reservation summary
+     * @param {Object} item 
+     */
+    showReservationSummary(item) {
+        this.setState({selectedItem: item, isReservDetsVisible: true, isSUDetsVisible: false});
+    }
+
     /**
      * To load task summary and show
      * @param {Object} item - Timeline task item object 
@@ -361,7 +373,7 @@ export class TimelineView extends Component {
      * Closes the SU details section
      */
     closeSUDets() {
-        this.setState({isSUDetsVisible: false, isTaskDetsVisible: false, canExtendSUList: true, canShrinkSUList: false});
+        this.setState({isSUDetsVisible: false, isReservDetsVisible: false, isTaskDetsVisible: false, canExtendSUList: true, canShrinkSUList: false});
     }
 
     /**
@@ -378,23 +390,34 @@ export class TimelineView extends Component {
      * @param {Object} item
      */
     onItemMouseOver(evt, item) {
-        const itemSU = _.find(this.state.suBlueprints, {id: (item.suId?item.suId:item.id)});
-        const itemStations = this.getSUStations(itemSU);
-        const itemStationGroups = this.groupSUStations(itemStations);
-        item.stations = {groups: "", counts: ""};
-        item.suName = itemSU.name;
-        for (const stationgroup of _.keys(itemStationGroups)) {
-            let groups = item.stations.groups;
-            let counts = item.stations.counts;
-            if (groups) {
-                groups = groups.concat("/");
-                counts = counts.concat("/");
+        if (item.type === "SCHEDULE" || item.type === "TASK") {
+            const itemSU = _.find(this.state.suBlueprints, {id: (item.suId?item.suId:item.id)});
+            const itemStations = this.getSUStations(itemSU);
+            const itemStationGroups = this.groupSUStations(itemStations);
+            item.stations = {groups: "", counts: ""};
+            item.suName = itemSU.name;
+            for (const stationgroup of _.keys(itemStationGroups)) {
+                let groups = item.stations.groups;
+                let counts = item.stations.counts;
+                if (groups) {
+                    groups = groups.concat("/");
+                    counts = counts.concat("/");
+                }
+                // Get station group 1st character and append 'S' to get CS,RS,IS 
+                groups = groups.concat(stationgroup.substring(0,1).concat('S'));
+                counts = counts.concat(itemStationGroups[stationgroup].length);
+                item.stations.groups = groups;
+                item.stations.counts = counts;
             }
-            // Get station group 1st character and append 'S' to get CS,RS,IS 
-            groups = groups.concat(stationgroup.substring(0,1).concat('S'));
-            counts = counts.concat(itemStationGroups[stationgroup].length);
-            item.stations.groups = groups;
-            item.stations.counts = counts;
+        }   else {
+            const reservation = _.find(this.reservations, {'id': parseInt(item.id.split("-")[1])});
+            const reservStations = reservation.specifications_doc.resources.stations;
+            const reservStationGroups = this.groupSUStations(reservStations);
+            item.name = reservation.name;
+            item.contact = reservation.specifications_doc.activity.contact
+            item.activity_type = reservation.specifications_doc.activity.type;
+            item.stations = reservStations;
+            item.planned = reservation.specifications_doc.activity.planned;
         }
         this.popOver.toggle(evt);
         this.setState({mouseOverItem: item});
@@ -463,7 +486,8 @@ export class TimelineView extends Component {
         // On range change close the Details pane
         // this.closeSUDets();
         // console.log(_.orderBy(group, ["parent", "id"], ['asc', 'desc']));
-        return {group: this.stationView? this.getStationsByGroupName() : _.orderBy(_.uniqBy(group, 'id'),["parent", "start"], ['asc', 'asc']), items: items};
+        group = this.state.stationView ? this.getStationsByGroupName() : _.orderBy(_.uniqBy(group, 'id'),["parent", "start"], ['asc', 'asc']);
+        return {group: group, items: items};
     }
 
     /**
@@ -849,13 +873,18 @@ export class TimelineView extends Component {
         //     return <AppLoader />
         // }
         const isSUDetsVisible = this.state.isSUDetsVisible;
+        const isReservDetsVisible = this.state.isReservDetsVisible;
         const isTaskDetsVisible = this.state.isTaskDetsVisible;
         const canExtendSUList = this.state.canExtendSUList;
         const canShrinkSUList = this.state.canShrinkSUList;
-        let suBlueprint = null;
+        let suBlueprint = null, reservation = null;
         if (isSUDetsVisible) {
             suBlueprint = _.find(this.state.suBlueprints, {id:  this.state.stationView?parseInt(this.state.selectedItem.id.split('-')[0]):this.state.selectedItem.id});
         }
+        if (isReservDetsVisible) {
+            reservation = _.find(this.reservations, {id: parseInt(this.state.selectedItem.id.split('-')[1])});
+            reservation.project = this.state.selectedItem.project;
+        }
         let mouseOverItem = this.state.mouseOverItem;
         return (
             <React.Fragment>
@@ -869,9 +898,10 @@ export class TimelineView extends Component {
                 { this.state.isLoading ? <AppLoader /> :
                         <div className="p-grid">
                             {/* SU List Panel */}
-                            <div className={isSUDetsVisible || isTaskDetsVisible || (canExtendSUList && !canShrinkSUList)?"col-lg-4 col-md-4 col-sm-12":((canExtendSUList && canShrinkSUList)?"col-lg-5 col-md-5 col-sm-12":"col-lg-6 col-md-6 col-sm-12")}
+                            <div className={isSUDetsVisible || isReservDetsVisible || isTaskDetsVisible || (canExtendSUList && !canShrinkSUList)?"col-lg-4 col-md-4 col-sm-12":((canExtendSUList && canShrinkSUList)?"col-lg-5 col-md-5 col-sm-12":"col-lg-6 col-md-6 col-sm-12")}
                                  style={{position: "inherit", borderRight: "5px solid #efefef", paddingTop: "10px"}}>
                                 <ViewTable 
+                                    viewInNewWindow
                                     data={this.state.suBlueprintList} 
                                     defaultcolumns={[{name: "Name",
                                                         start_time:
@@ -894,7 +924,7 @@ export class TimelineView extends Component {
                                 />
                             </div>
                             {/* Timeline Panel */}
-                            <div className={isSUDetsVisible || isTaskDetsVisible || (!canExtendSUList && canShrinkSUList)?"col-lg-5 col-md-5 col-sm-12":((canExtendSUList && canShrinkSUList)?"col-lg-7 col-md-7 col-sm-12":"col-lg-8 col-md-8 col-sm-12")}>
+                            <div className={isSUDetsVisible || isReservDetsVisible || isTaskDetsVisible || (!canExtendSUList && canShrinkSUList)?"col-lg-5 col-md-5 col-sm-12":((canExtendSUList && canShrinkSUList)?"col-lg-7 col-md-7 col-sm-12":"col-lg-8 col-md-8 col-sm-12")}>
                                 {/* Panel Resize buttons */}
                                 <div className="resize-div">
                                     <button className="p-link resize-btn" disabled={!this.state.canShrinkSUList} 
@@ -974,6 +1004,7 @@ export class TimelineView extends Component {
                                      style={{borderLeft: "1px solid #efefef", marginTop: "0px", backgroundColor: "#f2f2f2"}}>
                                     {this.state.isSummaryLoading?<AppLoader /> :
                                         <SchedulingUnitSummary schedulingUnit={suBlueprint} suTaskList={this.state.suTaskList}
+                                                viewInNewWindow        
                                                 constraintsTemplate={this.state.suConstraintTemplate}
                                                 stationGroup={this.state.stationGroup}
                                                 closeCallback={this.closeSUDets}></SchedulingUnitSummary>
@@ -988,12 +1019,20 @@ export class TimelineView extends Component {
                                     }
                                 </div>
                             }
+                            {this.state.isReservDetsVisible &&
+                                <div className="col-lg-3 col-md-3 col-sm-12" 
+                                     style={{borderLeft: "1px solid #efefef", marginTop: "0px", backgroundColor: "#f2f2f2"}}>
+                                    {this.state.isSummaryLoading?<AppLoader /> :
+                                        <ReservationSummary reservation={reservation} closeCallback={this.closeSUDets}></ReservationSummary>
+                                    }
+                                </div>
+                            }
                         </div>
                     
                 }
                 {/* SU Item Tooltip popover with SU status color */}
                 <OverlayPanel className="timeline-popover" ref={(el) => this.popOver = el} dismissable>
-                {mouseOverItem &&
+                {(mouseOverItem && (["SCHEDULE", "TASK"].indexOf(mouseOverItem.type)>=0)) &&
                     <div className={`p-grid su-${mouseOverItem.status}`} style={{width: '350px'}}>
                         <h3 className={`col-12 su-${mouseOverItem.status}-icon`}>{mouseOverItem.type==='SCHEDULE'?'Scheduling Unit ':'Task '}Overview</h3>
                         <hr></hr>
@@ -1028,6 +1067,37 @@ export class TimelineView extends Component {
                         <div className="col-7">{mouseOverItem.duration}</div>
                     </div>
                 }
+                {(mouseOverItem && mouseOverItem.type == "RESERVATION") &&
+                    <div className={`p-grid`} style={{width: '350px', backgroundColor: mouseOverItem.bgColor, color: mouseOverItem.color}}>
+                        <h3 className={`col-12`}>Reservation Overview</h3>
+                        <hr></hr>
+                        <label className={`col-5`} style={{color: mouseOverItem.color}}>Name:</label>
+                        <div className="col-7">{mouseOverItem.name}</div>
+                        <label className={`col-5`} style={{color: mouseOverItem.color}}>Description:</label>
+                        <div className="col-7">{mouseOverItem.desc}</div>
+                        <label className={`col-5`} style={{color: mouseOverItem.color}}>Type:</label>
+                        <div className="col-7">{mouseOverItem.activity_type}</div>
+                        <label className={`col-5`} style={{color: mouseOverItem.color}}>Stations:</label>
+                        {/* <div className="col-7"><ListBox options={mouseOverItem.stations} /></div> */}
+                        <div className="col-7 station-list">
+                            {mouseOverItem.stations.map((station, index) => (
+                                <div key={`stn-${index}`}>{station}</div>
+                            ))}
+                        </div>
+                        <label className={`col-5`} style={{color: mouseOverItem.color}}>Project:</label>
+                        <div className="col-7">{mouseOverItem.project?mouseOverItem.project:"-"}</div>
+                        <label className={`col-5`} style={{color: mouseOverItem.color}}>Start Time:</label>
+                        <div className="col-7">{mouseOverItem.start_time.format(UIConstants.CALENDAR_DATETIME_FORMAT)}</div>
+                        <label className={`col-5`} style={{color: mouseOverItem.color}}>End Time:</label>
+                        <div className="col-7">{mouseOverItem.end_time.format(UIConstants.CALENDAR_DATETIME_FORMAT)}</div>
+                        {/* <label className={`col-5`} style={{color: mouseOverItem.color}}>Stations:</label>
+                        <div className="col-7">{mouseOverItem.stations.groups}:{mouseOverItem.stations.counts}</div> */}
+                        <label className={`col-5`} style={{color: mouseOverItem.color}}>Duration:</label>
+                        <div className="col-7">{mouseOverItem.duration}</div>
+                        <label className={`col-5`} style={{color: mouseOverItem.color}}>Planned:</label>
+                        <div className="col-7">{mouseOverItem.planned?'Yes':'No'}</div>
+                    </div>
+                }
                 </OverlayPanel>
                 {!this.state.isLoading &&
                     <Websocket url={process.env.REACT_APP_WEBSOCKET_URL} onOpen={this.onConnect} onMessage={this.handleData} onClose={this.onDisconnect} /> }
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 fa976d92bec5bdf942d813a4a11d2daaea9185da..08322699a4c79cdcfe50a79e093874b69509c2ad 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
@@ -23,6 +23,9 @@ import SchedulingUnitSummary from '../Scheduling/summary';
 import UIConstants from '../../utils/ui.constants';
 import { OverlayPanel } from 'primereact/overlaypanel';
 import { TieredMenu } from 'primereact/tieredmenu';
+import { InputSwitch } from 'primereact/inputswitch';
+import { Dropdown } from 'primereact/dropdown';
+import ReservationSummary from './reservation.summary';
 
 // Color constant for status
 const STATUS_COLORS = { "ERROR": "FF0000", "CANCELLED": "#00FF00", "DEFINED": "#00BCD4", 
@@ -30,6 +33,9 @@ const STATUS_COLORS = { "ERROR": "FF0000", "CANCELLED": "#00FF00", "DEFINED": "#
                         "OBSERVED": "#cde", "PROCESSING": "#cddc39", "PROCESSED": "#fed",
                         "INGESTING": "#edc", "FINISHED": "#47d53d"};
 
+const RESERVATION_COLORS = {"true-true":{bgColor:"lightgrey", color:"#585859"}, "true-false":{bgColor:'#585859', color:"white"},
+                            "false-true":{bgColor:"#9b9999", color:"white"}, "false-false":{bgColor:"black", color:"white"}};
+
 /**
  * Scheduling Unit timeline view component to view SU List and timeline
  */
@@ -50,10 +56,13 @@ export class WeekTimelineView extends Component {
             selectedItem: null,
             suTaskList:[],
             isSummaryLoading: false,
-            stationGroup: []
+            stationGroup: [],
+            reservationEnabled: true
         }
         this.STATUS_BEFORE_SCHEDULED = ['defining', 'defined', 'schedulable'];  // Statuses before scheduled to get station_group
         this.mainStationGroups = {};
+        this.reservations = [];
+        this.reservationReasons = [];
         this.optionsMenu = React.createRef();
         this.menuOptions = [ {label:'Add Reservation', icon: "fa fa-", command: () => {this.selectOptionMenu('Add Reservation')}}, 
                             {label:'Reservation List', icon: "fa fa-", command: () => {this.selectOptionMenu('Reservation List')}},
@@ -65,9 +74,12 @@ export class WeekTimelineView extends Component {
         this.closeSUDets = this.closeSUDets.bind(this);
         this.onItemMouseOver = this.onItemMouseOver.bind(this);
         this.onItemMouseOut = this.onItemMouseOut.bind(this);
+        this.showSUSummary = this.showSUSummary.bind(this);
+        this.showReservationSummary = this.showReservationSummary.bind(this);
         this.dateRangeCallback = this.dateRangeCallback.bind(this);
         this.resizeSUList = this.resizeSUList.bind(this);
         this.suListFilterCallback = this.suListFilterCallback.bind(this);
+        this.addWeekReservations = this.addWeekReservations.bind(this);
         this.handleData = this.handleData.bind(this);
         this.addNewData = this.addNewData.bind(this);
         this.updateExistingData = this.updateExistingData.bind(this);
@@ -75,21 +87,33 @@ export class WeekTimelineView extends Component {
     }
 
     async componentDidMount() {
+        UtilService.getReservationTemplates().then(templates => {
+            this.reservationTemplate = templates.length>0?templates[0]:null;
+            if (this.reservationTemplate) {
+                let reasons = this.reservationTemplate.schema.properties.activity.properties.type.enum;
+                for (const reason of reasons) {
+                    this.reservationReasons.push({name: reason});
+                }
+            }
+        });
+        
         // Fetch all details from server and prepare data to pass to timeline and table components
         const promises = [  ProjectService.getProjectList(), 
                             ScheduleService.getSchedulingUnitsExtended('blueprint'),
                             ScheduleService.getSchedulingUnitDraft(),
                             ScheduleService.getSchedulingSets(),
                             UtilService.getUTC(),
-                            TaskService.getSubtaskTemplates()] ;
+                            TaskService.getSubtaskTemplates(),
+                            UtilService.getReservations()] ;
         Promise.all(promises).then(async(responses) => {
             this.subtaskTemplates = responses[5];
             const projects = responses[0];
             const suBlueprints = _.sortBy(responses[1], 'name');
             const suDrafts = responses[2].data.results;
             const suSets = responses[3]
-            const group = [], items = [];
+            let group = [], items = [];
             const currentUTC = moment.utc(responses[4]);
+            this.reservations = responses[6];
             const defaultStartTime = moment.utc().day(-2).hour(0).minutes(0).seconds(0);
             const defaultEndTime = moment.utc().day(8).hour(23).minutes(59).seconds(59);
             for (const count of _.range(11)) {
@@ -150,6 +174,9 @@ export class WeekTimelineView extends Component {
                     }
                 }
             }
+            if (this.state.reservationEnabled) {
+                items = this.addWeekReservations(items, defaultStartTime, defaultEndTime, currentUTC);
+            }
             // Get all scheduling constraint templates
             ScheduleService.getSchedulingConstraintTemplates()
                 .then(suConstraintTemplates => {
@@ -200,7 +227,19 @@ export class WeekTimelineView extends Component {
      * Callback function to pass to Timeline component for item click.
      * @param {Object} item 
      */
-    onItemClick(item) {
+     onItemClick(item) {
+        if (item.type === "SCHEDULE") { 
+            this.showSUSummary(item);
+        }   else if (item.type === "RESERVATION") {
+            this.showReservationSummary(item);
+        }
+    }
+
+    /**
+     * To load SU summary and show
+     * @param {Object} item - Timeline SU item object.
+     */
+    showSUSummary(item) {
         if (this.state.isSUDetsVisible && item.id===this.state.selectedItem.id) {
             this.closeSUDets();
         }   else {
@@ -242,11 +281,19 @@ export class WeekTimelineView extends Component {
         }
     }
 
+    /**
+     * To load and show Reservation summary
+     * @param {Object} item 
+     */
+     showReservationSummary(item) {
+        this.setState({selectedItem: item, isReservDetsVisible: true, isSUDetsVisible: false});
+    }
+
     /**
      * Closes the SU details section
      */
     closeSUDets() {
-        this.setState({isSUDetsVisible: false, canExtendSUList: true, canShrinkSUList: false});
+        this.setState({isSUDetsVisible: false, isReservDetsVisible: false, canExtendSUList: true, canShrinkSUList: false});
     }
 
     /**
@@ -263,23 +310,36 @@ export class WeekTimelineView extends Component {
      * @param {Object} item
      */
     onItemMouseOver(evt, item) {
-        const itemSU = _.find(this.state.suBlueprints, {id: parseInt(item.id.split("-")[0])});
-        const itemStations = itemSU.stations;
-        const itemStationGroups = this.groupSUStations(itemStations);
-        item.stations = {groups: "", counts: ""};
-        for (const stationgroup of _.keys(itemStationGroups)) {
-            let groups = item.stations.groups;
-            let counts = item.stations.counts;
-            if (groups) {
-                groups = groups.concat("/");
-                counts = counts.concat("/");
+        if (item.type === "SCHEDULE") {
+            const itemSU = _.find(this.state.suBlueprints, {id: parseInt(item.id.split("-")[0])});
+            const itemStations = itemSU.stations;
+            const itemStationGroups = this.groupSUStations(itemStations);
+            item.stations = {groups: "", counts: ""};
+            for (const stationgroup of _.keys(itemStationGroups)) {
+                let groups = item.stations.groups;
+                let counts = item.stations.counts;
+                if (groups) {
+                    groups = groups.concat("/");
+                    counts = counts.concat("/");
+                }
+                groups = groups.concat(stationgroup.substring(0,1).concat('S'));
+                counts = counts.concat(itemStationGroups[stationgroup].length);
+                item.stations.groups = groups;
+                item.stations.counts = counts;
+                item.suStartTime = moment.utc(itemSU.start_time);
+                item.suStopTime = moment.utc(itemSU.stop_time);
             }
-            groups = groups.concat(stationgroup.substring(0,1).concat('S'));
-            counts = counts.concat(itemStationGroups[stationgroup].length);
-            item.stations.groups = groups;
-            item.stations.counts = counts;
-            item.suStartTime = moment.utc(itemSU.start_time);
-            item.suStopTime = moment.utc(itemSU.stop_time);
+        }   else {
+            const reservation = _.find(this.reservations, {'id': parseInt(item.id.split("-")[1])});
+            const reservStations = reservation.specifications_doc.resources.stations;
+            const reservStationGroups = this.groupSUStations(reservStations);
+            item.name = reservation.name;
+            item.contact = reservation.specifications_doc.activity.contact
+            item.activity_type = reservation.specifications_doc.activity.type;
+            item.stations = reservStations;
+            item.planned = reservation.specifications_doc.activity.planned;
+            item.displayStartTime = moment.utc(reservation.start_time);
+            item.displayEndTime = reservation.duration?moment.utc(reservation.stop_time):null;
         }
         this.popOver.toggle(evt);
         this.setState({mouseOverItem: item});
@@ -362,6 +422,9 @@ export class WeekTimelineView extends Component {
                         }
                     } 
                 }
+                if (this.state.reservationEnabled) {
+                    items = this.addWeekReservations(items, startTime, endTime, currentUTC);
+                }
             }   else {
                 suBlueprintList = _.clone(this.state.suBlueprints);
                 group = this.state.group;
@@ -578,17 +641,148 @@ export class WeekTimelineView extends Component {
         });
     }
 
+    async showReservations(e) {
+        await this.setState({reservationEnabled: e.value});
+        let updatedItemGroupData = await this.dateRangeCallback(this.state.startTime, this.state.endTime, true);
+        this.timeline.updateTimeline(updatedItemGroupData);
+    }
+
+    /**
+     * Add Week Reservations during the visible timeline period
+     * @param {Array} items 
+     * @param {moment} startTime
+     * @param {moment} endTime
+     */
+     addWeekReservations(items, startTime, endTime, currentUTC) {
+        let reservations = this.reservations;
+        for (const reservation of reservations) {
+            const reservationStartTime = moment.utc(reservation.start_time);
+            const reservationEndTime = reservation.duration?reservationStartTime.clone().add(reservation.duration, 'seconds'):endTime;
+            const reservationSpec = reservation.specifications_doc;
+            if ( (reservationStartTime.isSame(startTime) 
+                    || reservationStartTime.isSame(endTime)                       
+                    || reservationStartTime.isBetween(startTime, endTime)
+                    || reservationEndTime.isSame(startTime) 
+                    || reservationEndTime.isSame(endTime)                       
+                    || reservationEndTime.isBetween(startTime, endTime)
+                    || (reservationStartTime.isSameOrBefore(startTime)
+                    && reservationEndTime.isSameOrAfter(endTime)))
+                    && (!this.state.reservationFilter ||                                        // No reservation filter added
+                        reservationSpec.activity.type === this.state.reservationFilter) ) {     // Reservation reason == Filtered reaseon
+                reservation.stop_time = reservationEndTime;
+                let splitReservations = this.splitReservations(reservation, startTime, endTime, currentUTC);
+                for (const splitReservation of splitReservations) {
+                    items.push(this.getReservationItem(splitReservation, currentUTC));
+                }
+                
+            }
+        }
+        return items;
+    }
+
+    /**
+     * Function to check if a reservation is for more than a day and split it to multiple objects to display in each day
+     * @param {Object} reservation - Reservation object
+     * @param {moment} startTime - moment object of the start datetime of the week view
+     * @param {moment} endTime  - moment object of the end datetime of the week view
+     * @returns 
+     */
+    splitReservations(reservation, startTime, endTime) {
+        const reservationStartTime = moment.utc(reservation.start_time);
+        let weekStartDate = moment(startTime).add(-1, 'day').startOf('day');
+        let weekEndDate = moment(endTime).add(1, 'day').startOf('day');
+        let splitReservations = [];
+        while(weekStartDate.add(1, 'days').diff(weekEndDate) < 0) {
+            const dayStart = weekStartDate.clone().startOf('day');
+            const dayEnd = weekStartDate.clone().endOf('day');
+            let splitReservation = null;
+            if (reservationStartTime.isSameOrBefore(dayStart) && 
+                (reservation.stop_time.isBetween(dayStart, dayEnd) ||
+                    reservation.stop_time.isSameOrAfter(dayEnd))) {
+                splitReservation = _.cloneDeep(reservation);
+                splitReservation.start_time = moment.utc(dayStart.format("YYYY-MM-DD HH:mm:ss"));
+            }   else if(reservationStartTime.isBetween(dayStart, dayEnd)) {
+                splitReservation = _.cloneDeep(reservation);
+                splitReservation.start_time = reservationStartTime;                
+            }
+            if (splitReservation) {
+                if (!reservation.stop_time || reservation.stop_time.isSameOrAfter(dayEnd)) {
+                    splitReservation.end_time = weekStartDate.clone().hour(23).minute(59).seconds(59);
+                }   else if (reservation.stop_time.isSameOrBefore(dayEnd)) {
+                    splitReservation.end_time = weekStartDate.clone().hour(reservation.stop_time.hours()).minutes(reservation.stop_time.minutes()).seconds(reservation.stop_time.seconds);
+                }
+                splitReservations.push(splitReservation);
+            }
+        }
+        return splitReservations;
+    }
+
+    /**
+     * Get reservation timeline item. If the reservation doesn't have duration, item endtime should be week endtime.
+     * @param {Object} reservation 
+     * @param {moment} endTime 
+     */
+    getReservationItem(reservation, displayDate) {
+        const reservationSpec = reservation.specifications_doc;
+        const group = moment.utc(reservation.start_time).format("MMM DD ddd");
+        const blockColor = RESERVATION_COLORS[this.getReservationType(reservationSpec.schedulability)];
+        let item = { id: `Res-${reservation.id}-${group}`,
+                        start_time: moment.utc(`${displayDate.format('YYYY-MM-DD')} ${reservation.start_time.format('HH:mm:ss')}`),
+                        end_time: moment.utc(`${displayDate.format('YYYY-MM-DD')} ${reservation.end_time.format('HH:mm:ss')}`),
+                        name: reservationSpec.activity.type, project: reservation.project_id,
+                        group: group,
+                        type: 'RESERVATION',
+                        title: `${reservationSpec.activity.type}${reservation.project_id?("-"+ reservation.project_id):""}`,
+                        desc: reservation.description,
+                        duration: reservation.duration?UnitConverter.getSecsToHHmmss(reservation.duration):"Unknown",
+                        bgColor: blockColor.bgColor, selectedBgColor: blockColor.bgColor, color: blockColor.color
+                    };
+        return item;
+    }
+
+    /**
+     * Get the schedule type from the schedulability object. It helps to get colors of the reservation blocks
+     * according to the type.
+     * @param {Object} schedulability 
+     */
+     getReservationType(schedulability) {
+        if (schedulability.manual && schedulability.dynamic) {
+            return 'true-true';
+        }   else if (!schedulability.manual && !schedulability.dynamic) {
+            return 'false-false';
+        }   else if (schedulability.manual && !schedulability.dynamic) {
+            return 'true-false';
+        }   else {
+            return 'false-true';
+        }
+    }
+
+    /**
+     * Set reservation filter
+     * @param {String} filter 
+     */
+    async setReservationFilter(filter) {
+        await this.setState({reservationFilter: filter});
+        let updatedItemGroupData = await this.dateRangeCallback(this.state.startTime, this.state.endTime, true);
+        this.timeline.updateTimeline(updatedItemGroupData);
+    }
+
     render() {
         if (this.state.redirect) {
             return <Redirect to={ {pathname: this.state.redirect} }></Redirect>
         }
         const isSUDetsVisible = this.state.isSUDetsVisible;
+        const isReservDetsVisible = this.state.isReservDetsVisible;
         const canExtendSUList = this.state.canExtendSUList;
         const canShrinkSUList = this.state.canShrinkSUList;
-        let suBlueprint = null;
+        let suBlueprint = null, reservation = null;
         if (isSUDetsVisible) {
             suBlueprint = _.find(this.state.suBlueprints, {id: parseInt(this.state.selectedItem.id.split('-')[0])});
         }
+        if (isReservDetsVisible) {
+            reservation = _.find(this.reservations, {id: parseInt(this.state.selectedItem.id.split('-')[1])});
+            reservation.project = this.state.selectedItem.project;
+        }
         const mouseOverItem = this.state.mouseOverItem;
         return (
             <React.Fragment>
@@ -609,9 +803,9 @@ export class WeekTimelineView extends Component {
                         </div> */}
                         <div className="p-grid">
                             {/* SU List Panel */}
-                            <div className={isSUDetsVisible || (canExtendSUList && !canShrinkSUList)?"col-lg-4 col-md-4 col-sm-12":((canExtendSUList && canShrinkSUList)?"col-lg-5 col-md-5 col-sm-12":"col-lg-6 col-md-6 col-sm-12")}
+                            <div className={isSUDetsVisible || isReservDetsVisible || (canExtendSUList && !canShrinkSUList)?"col-lg-4 col-md-4 col-sm-12":((canExtendSUList && canShrinkSUList)?"col-lg-5 col-md-5 col-sm-12":"col-lg-6 col-md-6 col-sm-12")}
                                  style={{position: "inherit", borderRight: "5px solid #efefef", paddingTop: "10px"}}>
-                                <ViewTable 
+                                <ViewTable viewInNewWindow
                                     data={this.state.suBlueprintList} 
                                     defaultcolumns={[{name: "Name",
                                                         start_time:"Start Time", stop_time:"End Time"}]}
@@ -628,7 +822,7 @@ export class WeekTimelineView extends Component {
                                 />
                             </div>
                             {/* Timeline Panel */}
-                            <div className={isSUDetsVisible || (!canExtendSUList && canShrinkSUList)?"col-lg-5 col-md-5 col-sm-12":((canExtendSUList && canShrinkSUList)?"col-lg-7 col-md-7 col-sm-12":"col-lg-8 col-md-8 col-sm-12")}>
+                            <div className={isSUDetsVisible || isReservDetsVisible || (!canExtendSUList && canShrinkSUList)?"col-lg-5 col-md-5 col-sm-12":((canExtendSUList && canShrinkSUList)?"col-lg-7 col-md-7 col-sm-12":"col-lg-8 col-md-8 col-sm-12")}>
                                 {/* Panel Resize buttons */}
                                 <div className="resize-div">
                                     <button className="p-link resize-btn" disabled={!this.state.canShrinkSUList} 
@@ -642,6 +836,28 @@ export class WeekTimelineView extends Component {
                                         <i className="pi pi-step-forward"></i>
                                     </button>
                                 </div> 
+                                <div className={`timeline-view-toolbar ${this.state.reservationEnabled && 'alignTimeLineHeader'}`}>
+                                    <div  className="sub-header">
+                                        <label >Show Reservations</label>
+                                        <InputSwitch checked={this.state.reservationEnabled} onChange={(e) => {this.showReservations(e)}} />                                       
+                                       
+                                    </div>
+                                
+                                    {this.state.reservationEnabled &&
+                                    <div className="sub-header">
+                                        <label style={{marginLeft: '20px'}}>Reservation</label>
+                                        <Dropdown optionLabel="name" optionValue="name" 
+                                                    style={{top:'2px'}}
+                                                    value={this.state.reservationFilter} 
+                                                    options={this.reservationReasons} 
+                                                    filter showClear={true} filterBy="name"
+                                                    onChange={(e) => {this.setReservationFilter(e.value)}} 
+                                                    placeholder="Reason"/>
+                                    
+                                    </div>
+                                    }
+                                </div>
+
                                 <Timeline ref={(tl)=>{this.timeline=tl}} 
                                         group={this.state.group} 
                                         items={this.state.items}
@@ -665,6 +881,7 @@ export class WeekTimelineView extends Component {
                                      style={{borderLeft: "1px solid #efefef", marginTop: "0px", backgroundColor: "#f2f2f2"}}>
                                     {this.state.isSummaryLoading?<AppLoader /> :
                                         <SchedulingUnitSummary schedulingUnit={suBlueprint} suTaskList={this.state.suTaskList}
+                                                viewInNewWindow
                                                 constraintsTemplate={this.state.suConstraintTemplate}
                                                 closeCallback={this.closeSUDets}
                                                 stationGroup={this.state.stationGroup}
@@ -672,13 +889,20 @@ export class WeekTimelineView extends Component {
                                     }
                                 </div>
                             }  
-                        
+                            {this.state.isReservDetsVisible &&
+                                <div className="col-lg-3 col-md-3 col-sm-12" 
+                                     style={{borderLeft: "1px solid #efefef", marginTop: "0px", backgroundColor: "#f2f2f2"}}>
+                                    {this.state.isSummaryLoading?<AppLoader /> :
+                                        <ReservationSummary reservation={reservation} location={this.props.location} closeCallback={this.closeSUDets}></ReservationSummary>
+                                    }
+                                </div>
+                            }
                         </div>
                     </>
                 }
                 {/* SU Item Tooltip popover with SU status color */}
                 <OverlayPanel className="timeline-popover" ref={(el) => this.popOver = el} dismissable>
-                {mouseOverItem &&
+                {mouseOverItem  && mouseOverItem.type == "SCHEDULE" &&
                     <div className={`p-grid su-${mouseOverItem.status}`} style={{width: '350px'}}>
                         <label className={`col-5 su-${mouseOverItem.status}-icon`}>Project:</label>
                         <div className="col-7">{mouseOverItem.project}</div>
@@ -700,6 +924,37 @@ export class WeekTimelineView extends Component {
                         <div className="col-7">{mouseOverItem.duration}</div>
                     </div>
                 }
+                {(mouseOverItem && mouseOverItem.type == "RESERVATION") &&
+                    <div className={`p-grid`} style={{width: '350px', backgroundColor: mouseOverItem.bgColor, color: mouseOverItem.color}}>
+                        <h3 className={`col-12`}>Reservation Overview</h3>
+                        <hr></hr>
+                        <label className={`col-5`} style={{color: mouseOverItem.color}}>Name:</label>
+                        <div className="col-7">{mouseOverItem.name}</div>
+                        <label className={`col-5`} style={{color: mouseOverItem.color}}>Description:</label>
+                        <div className="col-7">{mouseOverItem.desc}</div>
+                        <label className={`col-5`} style={{color: mouseOverItem.color}}>Type:</label>
+                        <div className="col-7">{mouseOverItem.activity_type}</div>
+                        <label className={`col-5`} style={{color: mouseOverItem.color}}>Stations:</label>
+                        {/* <div className="col-7"><ListBox options={mouseOverItem.stations} /></div> */}
+                        <div className="col-7 station-list">
+                            {mouseOverItem.stations.map((station, index) => (
+                                <div key={`stn-${index}`}>{station}</div>
+                            ))}
+                        </div>
+                        <label className={`col-5`} style={{color: mouseOverItem.color}}>Project:</label>
+                        <div className="col-7">{mouseOverItem.project?mouseOverItem.project:"-"}</div>
+                        <label className={`col-5`} style={{color: mouseOverItem.color}}>Start Time:</label>
+                        <div className="col-7">{mouseOverItem.displayStartTime.format(UIConstants.CALENDAR_DATETIME_FORMAT)}</div>
+                        <label className={`col-5`} style={{color: mouseOverItem.color}}>End Time:</label>
+                        <div className="col-7">{mouseOverItem.displayEndTime?mouseOverItem.displayEndTime.format(UIConstants.CALENDAR_DATETIME_FORMAT):'Unknown'}</div>
+                        {/* <label className={`col-5`} style={{color: mouseOverItem.color}}>Stations:</label>
+                        <div className="col-7">{mouseOverItem.stations.groups}:{mouseOverItem.stations.counts}</div> */}
+                        <label className={`col-5`} style={{color: mouseOverItem.color}}>Duration:</label>
+                        <div className="col-7">{mouseOverItem.duration}</div>
+                        <label className={`col-5`} style={{color: mouseOverItem.color}}>Planned:</label>
+                        <div className="col-7">{mouseOverItem.planned?'Yes':'No'}</div>
+                    </div>
+                }
                 </OverlayPanel>
                 {/* Open Websocket after loading all initial data */}
                 {!this.state.isLoading &&
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/index.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/index.js
index c296c76ff16c1d6ba260e04723bdb12ce8d9158d..286d0c21dd0a1a496adfb6f1be8a519bd5effdd9 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/index.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/index.js
@@ -9,12 +9,13 @@ import {NotFound} from '../layout/components/NotFound';
 import {ProjectList, ProjectCreate, ProjectView, ProjectEdit} from './Project';
 import {Dashboard} from './Dashboard';
 import {Scheduling} from './Scheduling';
-import {TaskEdit, TaskView, DataProduct} from './Task';
+import {TaskEdit, TaskView, DataProduct, TaskList} from './Task';
 import ViewSchedulingUnit from './Scheduling/ViewSchedulingUnit'
 import SchedulingUnitCreate from './Scheduling/create';
 import EditSchedulingUnit from './Scheduling/edit';
 import { CycleList, CycleCreate, CycleView, CycleEdit } from './Cycle';
 import { TimelineView, WeekTimelineView, ReservationCreate, ReservationList } from './Timeline';
+import { FindObjectResult } from './Search/'
 import SchedulingSetCreate from './Scheduling/excelview.schedulingset';
 import Workflow from './Workflow';
 import { Growl } from 'primereact/components/growl/Growl';
@@ -41,9 +42,9 @@ export const routes = [
         title: 'Scheduling Unit - Add'
     },{
         path: "/task",
-        component: TaskView,
+        component: TaskList,
         name: 'Task',
-        title: 'Task-View'
+        title: 'Task-List'
     },{
         path: "/task/view",
         component: TaskView,
@@ -165,6 +166,12 @@ export const routes = [
         component: ReservationCreate,
         name: 'Reservation Add',
         title: 'Reservation - Add'
+    },
+    {
+        path: "/find/object/:type/:id",
+        component: FindObjectResult,
+        name: 'Find Object',
+        title: 'Find Object'
     }
 ];
 
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/services/task.service.js b/SAS/TMSS/frontend/tmss_webapp/src/services/task.service.js
index 3b99780c7ae8fe731e2311362665cfe273c61d8b..fd4b6d769ecc53b022be3da580317ebbae11a24d 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/services/task.service.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/services/task.service.js
@@ -2,31 +2,39 @@ const axios = require('axios');
 
 const TaskService = {
     getTaskDetails: async function (taskType, taskId) {
-        try {
-          const url = taskType === 'blueprint'? '/api/task_blueprint/': '/api/task_draft/';
-          const response = await axios.get(url + taskId);
-          response.data.predecessors = [];
-          response.data.successors = [];
-          if (taskType === 'blueprint') {
-            response.data.blueprints = [];
-          } else {
-            response.data.draftName = null;
-          }
-          return this.getTaskRelationsByTask(taskType, response.data)
-                  .then(relations => {
-                    response.data.predecessors = relations.predecessors;
-                    response.data.successors = relations.successors;
-                    if (taskType === 'draft') {
-                      response.data.blueprints = relations.blueprints;
-                    } else {
-                      response.data.draftObject = relations.draft;
-                    }
-                    return response.data;
-                  });
-          
-        } catch (error) {
-          console.error(error);
+      try {
+        const responseData = await this.getTask(taskType, taskId); 
+        responseData.predecessors = [];
+        responseData.successors = [];
+        if (taskType === 'blueprint') {
+          responseData.blueprints = [];
+        } else {
+          responseData.draftName = null;
         }
+        return this.getTaskRelationsByTask(taskType, responseData)
+            .then(relations => {
+            responseData.predecessors = relations.predecessors;
+            responseData.successors = relations.successors;
+            if (taskType === 'draft') {
+              responseData.blueprints = relations.blueprints;
+            } else {
+              responseData.draftObject = relations.draft;
+            }
+            return responseData;
+        });
+        
+      } catch (error) {
+        console.error(error);
+      }
+    },
+    getTask : async function (taskType, taskId) {
+      try {
+        const url = taskType === 'blueprint'? '/api/task_blueprint/': '/api/task_draft/';
+        const response = await axios.get(url + taskId);
+        return response.data;
+      } catch (error) {
+        console.error(error);
+      }
     },
     getTaskTemplate: async function(templateId) {
       try {
@@ -53,6 +61,24 @@ const TaskService = {
         console.error(error);
       }
     },
+    getTaskDraftList: async function() {
+      try {
+        const url = `/api/task_draft`;
+        const response = await axios.get(url);
+        return response.data.results;
+      } catch (error) {
+        console.error(error);
+      }
+    },
+    getTaskBlueprintList: async function() {
+      try {
+        const url = `/api/task_blueprint`;
+        const response = await axios.get(url);
+        return response.data.results;
+      } catch (error) {
+        console.error(error);
+      }
+    },
     updateTask: async function(type, task) {
       try {
         const response = await axios.put(('/api/task_draft/' + task.id + "/"), task);
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/services/util.service.js b/SAS/TMSS/frontend/tmss_webapp/src/services/util.service.js
index d46b2fba3e90b785a60bf6f1f95e9ac0edc0dc74..036165fc7138afbbed3f02de55ff5a1564b4f438 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/services/util.service.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/services/util.service.js
@@ -64,6 +64,19 @@ const UtilService = {
         return  null;
       }
     },
+    /**
+     * 
+     * @param {String} timestamps - Date in 'YYYY-MM-DD' format. Multiples dates are separated by commas (2020-08-15, 2021-01-26).
+     */
+    getAllStationSunTimings: async(timestamps) => {
+      try {
+        let allStations = (await axios.get("/api/station_groups/stations/1/All")).data.stations;
+        let allStationSuntimes = (await axios.get(`/api/util/sun_rise_and_set?stations=${allStations.join(",")}&timestamps=${timestamps}`)).data;
+        return allStationSuntimes;
+      } catch(error) {
+        console.error(error);
+      }
+    },
     /** Gets all reservations in the system */
     getReservations: async() => {
       try {