Repository: meltano/meltano

Issue:
Bug: Meltano UI fails to load schedules
Looks like a bug in `controllers/orchestration.py`.

```
  File "/usr/local/lib/python3.9/site-packages/meltano/api/controllers/orchestrations.py", line 497, in get_pipeline_schedules
    if schedule.job and jobs_in_list:
AttributeError: 'dict' object has no attribute 'job'
```

```
(poe-UJy2mlGs-py3.8) aj@ajs-macbook-pro aj-dataops-personal % docker run -v "$(pwd)":/project -w /project -p 5000:5000 meltano/meltano:SHA-2a4d5aea01443cdb161de1c7af9873d2c7189d1b ui
2022-06-10T20:53:44.598916Z [info     ] Environment 'dev' is active
2022-06-10T20:53:45.437809Z [info     ] All workers started.
[2022-06-10 20:53:46,191] [9|MainThread|gunicorn.error] [INFO] Starting gunicorn 19.10.0
[2022-06-10 20:53:46,197] [9|MainThread|gunicorn.error] [INFO] Listening at: http://0.0.0.0:5000 (9)
[2022-06-10 20:53:46,197] [9|MainThread|gunicorn.error] [INFO] Using worker: sync
/usr/local/lib/python3.9/os.py:1023: RuntimeWarning: line buffering (buffering=1) isn't supported in binary mode, the default buffer size will be used
  return io.open(fd, *args, **kwargs)
[2022-06-10 20:53:46,202] [10|MainThread|gunicorn.error] [INFO] Booting worker with pid: 10
[2022-06-10 20:53:46,299] [11|MainThread|gunicorn.error] [INFO] Booting worker with pid: 11
[2022-06-10 20:53:46,342] [12|MainThread|gunicorn.error] [INFO] Booting worker with pid: 12
[2022-06-10 20:53:46,369] [13|MainThread|gunicorn.error] [INFO] Booting worker with pid: 13
Meltano UI is now available at http://localhost:5000
2022-06-10T20:53:52.973947Z [error    ] Exception on /api/v1/orchestrations/pipeline-schedules [GET] 
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.9/site-packages/flask_restful/__init__.py", line 271, in error_router
    return original_handler(e)
  File "/usr/local/lib/python3.9/site-packages/flask_restful/__init__.py", line 271, in error_router
    return original_handler(e)
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python3.9/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/local/lib/python3.9/site-packages/meltano/api/controllers/orchestrations.py", line 497, in get_pipeline_schedules
    if schedule.job and jobs_in_list:
AttributeError: 'dict' object has no attribute 'job'
```

## Context:

This occured on my personal dataops project: https://github.com/aaronsteers/aj-dataops-personal/blob/main/meltano.yml

I was testing the docker image when I discovered this.

Commenting out my `schedules:` entry resolved the issue.



Discussion:
Hello,

This is actually a reason we are not migrating to Meltano2.0
Even by using the documentation and creating the schedules and jobs, we can't make it work.
I also tried to add the job flag in my different schedules, but it didn't succeed.


Resolving patch:
diff --git a/src/meltano/api/controllers/orchestrations.py b/src/meltano/api/controllers/orchestrations.py
--- a/src/meltano/api/controllers/orchestrations.py
+++ b/src/meltano/api/controllers/orchestrations.py
@@ -494,9 +494,11 @@ def get_pipeline_schedules():
     formatted_schedules = []
 
     for schedule in schedules:
-        if schedule.job and jobs_in_list:
+        if schedule.get("job") and jobs_in_list:
+            # we only return API results for scheduled jobs if the feature flag is explicitly enabled
+            # as the UI is not job aware yet.
             formatted_schedules.append(schedule)
-        elif schedule.elt_schedule:
+        elif not schedule.get("job"):  # a legacy elt task
             finder = JobFinder(schedule["name"])
             state_job = finder.latest(db.session)
             schedule["has_error"] = state_job.has_error() if state_job else False


Test patch: