OpenOrchestrator 1.1.0__py3-none-any.whl → 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- OpenOrchestrator/database/db_util.py +1 -3
- OpenOrchestrator/orchestrator/application.py +18 -1
- OpenOrchestrator/orchestrator/tabs/queue_tab.py +1 -1
- OpenOrchestrator/orchestrator/tabs/trigger_tab.py +1 -1
- OpenOrchestrator/scheduler/application.py +1 -1
- OpenOrchestrator/scheduler/run_tab.py +85 -87
- OpenOrchestrator/scheduler/runner.py +28 -18
- {OpenOrchestrator-1.1.0.dist-info → OpenOrchestrator-1.2.0.dist-info}/METADATA +1 -1
- {OpenOrchestrator-1.1.0.dist-info → OpenOrchestrator-1.2.0.dist-info}/RECORD +12 -12
- {OpenOrchestrator-1.1.0.dist-info → OpenOrchestrator-1.2.0.dist-info}/LICENSE +0 -0
- {OpenOrchestrator-1.1.0.dist-info → OpenOrchestrator-1.2.0.dist-info}/WHEEL +0 -0
- {OpenOrchestrator-1.1.0.dist-info → OpenOrchestrator-1.2.0.dist-info}/top_level.txt +0 -0
@@ -601,9 +601,7 @@ def begin_scheduled_trigger(trigger_id: str) -> bool:
|
|
601
601
|
|
602
602
|
trigger.process_status = TriggerStatus.RUNNING
|
603
603
|
trigger.last_run = datetime.now()
|
604
|
-
|
605
|
-
next_run = croniter(trigger.cron_expr, trigger.next_run).get_next(datetime)
|
606
|
-
trigger.next_run = next_run
|
604
|
+
trigger.next_run = croniter(trigger.cron_expr, datetime.now()).get_next(datetime)
|
607
605
|
|
608
606
|
session.commit()
|
609
607
|
return True
|
@@ -1,6 +1,8 @@
|
|
1
1
|
"""This module is the entry point for the Orchestrator app. It contains a single class
|
2
2
|
that when created starts the application."""
|
3
3
|
|
4
|
+
import socket
|
5
|
+
|
4
6
|
from nicegui import ui, app
|
5
7
|
|
6
8
|
from OpenOrchestrator.orchestrator.tabs.trigger_tab import TriggerTab
|
@@ -39,7 +41,7 @@ class Application():
|
|
39
41
|
app.on_connect(self.update_loop)
|
40
42
|
app.on_disconnect(app.shutdown)
|
41
43
|
app.on_exception(lambda exc: ui.notify(exc, type='negative'))
|
42
|
-
ui.run(title="Orchestrator", favicon='🤖', native=False, port=
|
44
|
+
ui.run(title="Orchestrator", favicon='🤖', native=False, port=get_free_port(), reload=False)
|
43
45
|
|
44
46
|
def update_tab(self):
|
45
47
|
"""Update the date in the currently selected tab."""
|
@@ -73,5 +75,20 @@ class Application():
|
|
73
75
|
''')
|
74
76
|
|
75
77
|
|
78
|
+
def get_free_port():
|
79
|
+
"""Get a free port by creating a new socket and bind it
|
80
|
+
on port 0 allowing the os to select the port.
|
81
|
+
https://docs.python.org/3/library/socket.html#socket.create_connection
|
82
|
+
|
83
|
+
Returns:
|
84
|
+
A port number that should be free to use.
|
85
|
+
"""
|
86
|
+
with socket.socket() as sock:
|
87
|
+
sock.bind(("", 0))
|
88
|
+
port = sock.getsockname()[1]
|
89
|
+
|
90
|
+
return port
|
91
|
+
|
92
|
+
|
76
93
|
if __name__ in {'__main__', '__mp_main__'}:
|
77
94
|
Application()
|
@@ -33,7 +33,7 @@ class QueueTab():
|
|
33
33
|
"""The 'Queues' tab object. It contains tables and buttons for dealing with queues."""
|
34
34
|
def __init__(self, tab_name: str) -> None:
|
35
35
|
with ui.tab_panel(tab_name):
|
36
|
-
self.queue_table = ui.table(title="Queues", columns=QUEUE_COLUMNS, rows=[], row_key='Queue Name', pagination=
|
36
|
+
self.queue_table = ui.table(title="Queues", columns=QUEUE_COLUMNS, rows=[], row_key='Queue Name', pagination=50).classes("w-full")
|
37
37
|
self.queue_table.on("rowClick", self._row_click)
|
38
38
|
|
39
39
|
def update(self):
|
@@ -30,7 +30,7 @@ class TriggerTab():
|
|
30
30
|
ui.button("New Scheduled Trigger", icon="add", on_click=lambda e: TriggerPopup(self, TriggerType.SCHEDULED))
|
31
31
|
ui.button("New Queue Trigger", icon="add", on_click=lambda e: TriggerPopup(self, TriggerType.QUEUE))
|
32
32
|
|
33
|
-
self.trigger_table = ui.table(COLUMNS, [], title="Triggers", pagination=
|
33
|
+
self.trigger_table = ui.table(COLUMNS, [], title="Triggers", pagination=50, row_key='ID').classes("w-full")
|
34
34
|
self.trigger_table.on('rowClick', self._row_click)
|
35
35
|
|
36
36
|
self.add_column_colors()
|
@@ -26,7 +26,7 @@ class Application(tkinter.Tk):
|
|
26
26
|
notebook = ttk.Notebook(self)
|
27
27
|
notebook.pack(expand=True, fill='both')
|
28
28
|
|
29
|
-
run_tab_ = run_tab.
|
29
|
+
run_tab_ = run_tab.RunTab(notebook, self)
|
30
30
|
settings_tab_ = settings_tab.create_tab(notebook)
|
31
31
|
|
32
32
|
notebook.add(run_tab_, text='Run')
|
@@ -1,124 +1,123 @@
|
|
1
1
|
"""This module is responsible for the layout and functionality of the run tab
|
2
2
|
in Scheduler."""
|
3
3
|
|
4
|
+
from __future__ import annotations
|
5
|
+
from typing import TYPE_CHECKING
|
6
|
+
|
4
7
|
import tkinter
|
5
8
|
from tkinter import ttk
|
6
9
|
import sys
|
7
10
|
|
11
|
+
from sqlalchemy import exc as alc_exc
|
12
|
+
|
8
13
|
from OpenOrchestrator.common import crypto_util
|
9
14
|
from OpenOrchestrator.database import db_util
|
10
15
|
from OpenOrchestrator.scheduler import runner
|
11
16
|
|
17
|
+
if TYPE_CHECKING:
|
18
|
+
from OpenOrchestrator.scheduler.application import Application
|
12
19
|
|
13
|
-
def create_tab(parent: ttk.Notebook, app) -> ttk.Frame:
|
14
|
-
"""Create a new Run tab object.
|
15
|
-
|
16
|
-
Args:
|
17
|
-
parent: The ttk.Notebook object that this tab is a child of.
|
18
|
-
app: The Scheduler application object.
|
19
|
-
|
20
|
-
Returns:
|
21
|
-
ttk.Frame: The created tab object as a ttk.Frame.
|
22
|
-
"""
|
23
|
-
tab = ttk.Frame(parent)
|
24
|
-
tab.pack(fill='both', expand=True)
|
25
|
-
|
26
|
-
status_label = ttk.Label(tab, text="State: Paused")
|
27
|
-
status_label.pack()
|
28
|
-
|
29
|
-
ttk.Button(tab, text="Run", command=lambda: run(app, status_label)).pack()
|
30
|
-
ttk.Button(tab, text="Pause", command=lambda: pause(app, status_label)).pack()
|
31
|
-
|
32
|
-
# Text area
|
33
|
-
text_frame = tkinter.Frame(tab)
|
34
|
-
text_frame.pack()
|
35
20
|
|
36
|
-
|
37
|
-
|
21
|
+
# pylint: disable-next=too-many-ancestors
|
22
|
+
class RunTab(ttk.Frame):
|
23
|
+
"""A ttk.frame object containing the functionality of the run tab in Scheduler."""
|
24
|
+
def __init__(self, parent: ttk.Notebook, app: Application):
|
25
|
+
super().__init__(parent)
|
26
|
+
self.pack(fill='both', expand=True)
|
38
27
|
|
39
|
-
|
40
|
-
text_yscroll.pack(side='right', fill='y')
|
41
|
-
text_area.configure(yscrollcommand=text_yscroll.set)
|
28
|
+
self.app = app
|
42
29
|
|
43
|
-
|
44
|
-
|
45
|
-
|
30
|
+
s = ttk.Style()
|
31
|
+
s.configure('my.TButton', font=('Helvetica Bold', 24))
|
32
|
+
self.button = ttk.Button(self, text="Run", command=self.button_click, style='my.TButton')
|
33
|
+
self.button.pack()
|
46
34
|
|
47
|
-
|
35
|
+
# Text area
|
36
|
+
text_frame = tkinter.Frame(self)
|
37
|
+
text_frame.pack()
|
48
38
|
|
49
|
-
|
39
|
+
self.text_area = tkinter.Text(text_frame, state='disabled', wrap='none')
|
50
40
|
|
41
|
+
# Redirect stdout to the text area instead of console
|
42
|
+
sys.stdout.write = self.print_text
|
51
43
|
|
52
|
-
|
53
|
-
|
44
|
+
# Add scroll bars to text area
|
45
|
+
text_yscroll = ttk.Scrollbar(text_frame, orient='vertical', command=self.text_area.yview)
|
46
|
+
text_yscroll.pack(side='right', fill='y')
|
47
|
+
self.text_area.configure(yscrollcommand=text_yscroll.set)
|
54
48
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
"""
|
59
|
-
if db_util.get_conn_string() is None:
|
60
|
-
print("Can't start without a valid connection string. Go to the settings tab to configure the connection string")
|
61
|
-
return
|
62
|
-
if crypto_util.get_key() is None:
|
63
|
-
print("Can't start without a valid encryption key. Go to the settings tab to configure the encryption key")
|
64
|
-
return
|
65
|
-
|
66
|
-
if not app.running:
|
67
|
-
status_label.configure(text='State: Running')
|
68
|
-
print('Running...\n')
|
69
|
-
app.running = True
|
49
|
+
text_xscroll = ttk.Scrollbar(text_frame, orient='horizontal', command=self.text_area.xview)
|
50
|
+
text_xscroll.pack(side='bottom', fill='x')
|
51
|
+
self.text_area.configure(xscrollcommand=text_xscroll.set)
|
70
52
|
|
71
|
-
|
72
|
-
if app.tk.call('after', 'info') == '':
|
73
|
-
app.after(0, loop, app)
|
53
|
+
self.text_area.pack()
|
74
54
|
|
55
|
+
def button_click(self):
|
56
|
+
"""Callback for when the run/pause button is clicked."""
|
57
|
+
if self.app.running:
|
58
|
+
self.pause()
|
59
|
+
else:
|
60
|
+
self.run()
|
75
61
|
|
76
|
-
def pause(
|
77
|
-
|
78
|
-
|
79
|
-
Args:
|
80
|
-
app: The Scheduler application object.
|
81
|
-
status_label: The label showing the current status.
|
82
|
-
"""
|
83
|
-
if app.running:
|
84
|
-
status_label.configure(text="State: Paused")
|
62
|
+
def pause(self):
|
63
|
+
"""Stops the Scheduler and sets the app's status to 'paused'."""
|
64
|
+
self.button.configure(text="Run")
|
85
65
|
print('Paused... Please wait for all processes to stop before closing the application\n')
|
86
|
-
app.running = False
|
66
|
+
self.app.running = False
|
67
|
+
|
68
|
+
def run(self):
|
69
|
+
"""Starts the Scheduler and sets the app's status to 'running'."""
|
70
|
+
if db_util.get_conn_string() is None:
|
71
|
+
print("Can't start without a valid connection string. Go to the settings tab to configure the connection string")
|
72
|
+
return
|
73
|
+
if crypto_util.get_key() is None:
|
74
|
+
print("Can't start without a valid encryption key. Go to the settings tab to configure the encryption key")
|
75
|
+
return
|
76
|
+
|
77
|
+
self.button.configure(text="Pause")
|
78
|
+
print('Running...\n')
|
79
|
+
self.app.running = True
|
87
80
|
|
81
|
+
# Only start a new loop if it's not already running
|
82
|
+
if self.app.tk.call('after', 'info') == '':
|
83
|
+
self.app.after(0, loop, self.app)
|
88
84
|
|
89
|
-
def print_text(
|
90
|
-
|
91
|
-
|
85
|
+
def print_text(self, text: str) -> None:
|
86
|
+
"""Appends text to the text area.
|
87
|
+
Is used to replace the functionality of sys.stdout.write (print).
|
92
88
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
text_widget.insert('end', text)
|
89
|
+
Args:
|
90
|
+
string: The string to append.
|
91
|
+
"""
|
92
|
+
# Insert text at the end
|
93
|
+
self.text_area.configure(state='normal')
|
94
|
+
self.text_area.insert('end', text)
|
100
95
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
96
|
+
# If the number of lines are above 1000 delete 10 lines from the top
|
97
|
+
num_lines = int(self.text_area.index('end').split('.', maxsplit=1)[0])
|
98
|
+
if num_lines > 1000:
|
99
|
+
self.text_area.delete("1.0", "10.0")
|
105
100
|
|
106
|
-
|
107
|
-
|
108
|
-
|
101
|
+
# Scroll to end
|
102
|
+
self.text_area.see('end')
|
103
|
+
self.text_area.configure(state='disabled')
|
109
104
|
|
110
105
|
|
111
|
-
def loop(app) -> None:
|
106
|
+
def loop(app: Application) -> None:
|
112
107
|
"""The main loop function of the Scheduler.
|
113
108
|
Checks heartbeats, check triggers, and schedules the next loop.
|
114
109
|
|
115
110
|
Args:
|
116
111
|
app: The Scheduler Application object.
|
117
112
|
"""
|
118
|
-
|
113
|
+
try:
|
114
|
+
check_heartbeats(app)
|
115
|
+
|
116
|
+
if app.running:
|
117
|
+
check_triggers(app)
|
119
118
|
|
120
|
-
|
121
|
-
|
119
|
+
except alc_exc.OperationalError:
|
120
|
+
print("Couldn't connect to database.")
|
122
121
|
|
123
122
|
if len(app.running_jobs) == 0:
|
124
123
|
print("Doing cleanup...")
|
@@ -132,7 +131,7 @@ def loop(app) -> None:
|
|
132
131
|
print("Scheduler is paused and no more processes are running.")
|
133
132
|
|
134
133
|
|
135
|
-
def check_heartbeats(app) -> None:
|
134
|
+
def check_heartbeats(app: Application) -> None:
|
136
135
|
"""Check if any running jobs are still running, failed or done.
|
137
136
|
|
138
137
|
Args:
|
@@ -141,8 +140,6 @@ def check_heartbeats(app) -> None:
|
|
141
140
|
print('Checking heartbeats...')
|
142
141
|
for job in app.running_jobs:
|
143
142
|
if job.process.poll() is not None:
|
144
|
-
app.running_jobs.remove(job)
|
145
|
-
|
146
143
|
if job.process.returncode == 0:
|
147
144
|
print(f"Process '{job.trigger.process_name}' is done")
|
148
145
|
runner.end_job(job)
|
@@ -150,11 +147,12 @@ def check_heartbeats(app) -> None:
|
|
150
147
|
print(f"Process '{job.trigger.process_name}' failed. Check process log for more info.")
|
151
148
|
runner.fail_job(job)
|
152
149
|
|
150
|
+
app.running_jobs.remove(job)
|
153
151
|
else:
|
154
152
|
print(f"Process '{job.trigger.process_name}' is still running")
|
155
153
|
|
156
154
|
|
157
|
-
def check_triggers(app) -> None:
|
155
|
+
def check_triggers(app: Application) -> None:
|
158
156
|
"""Checks any process is blocking
|
159
157
|
and if not checks if any trigger should be run.
|
160
158
|
|
@@ -16,6 +16,7 @@ class Job():
|
|
16
16
|
"""An object that holds information about a running job."""
|
17
17
|
process: subprocess.Popen
|
18
18
|
trigger: Trigger
|
19
|
+
process_folder: str
|
19
20
|
|
20
21
|
|
21
22
|
def poll_triggers(app) -> Job | None:
|
@@ -66,10 +67,7 @@ def run_single_trigger(trigger: SingleTrigger) -> Job | None:
|
|
66
67
|
print('Running trigger: ', trigger.trigger_name)
|
67
68
|
|
68
69
|
if db_util.begin_single_trigger(trigger.id):
|
69
|
-
|
70
|
-
|
71
|
-
if process is not None:
|
72
|
-
return Job(process, trigger)
|
70
|
+
return run_process(trigger)
|
73
71
|
|
74
72
|
return None
|
75
73
|
|
@@ -88,10 +86,7 @@ def run_scheduled_trigger(trigger: ScheduledTrigger) -> Job | None:
|
|
88
86
|
print('Running trigger: ', trigger.trigger_name)
|
89
87
|
|
90
88
|
if db_util.begin_scheduled_trigger(trigger.id):
|
91
|
-
|
92
|
-
|
93
|
-
if process is not None:
|
94
|
-
return Job(process, trigger)
|
89
|
+
return run_process(trigger)
|
95
90
|
|
96
91
|
return None
|
97
92
|
|
@@ -109,10 +104,7 @@ def run_queue_trigger(trigger: QueueTrigger) -> Job | None:
|
|
109
104
|
print('Running trigger: ', trigger.trigger_name)
|
110
105
|
|
111
106
|
if db_util.begin_queue_trigger(trigger.id):
|
112
|
-
|
113
|
-
|
114
|
-
if process is not None:
|
115
|
-
return Job(process, trigger)
|
107
|
+
return run_process(trigger)
|
116
108
|
|
117
109
|
return None
|
118
110
|
|
@@ -142,7 +134,7 @@ def clone_git_repo(repo_url: str) -> str:
|
|
142
134
|
def clear_repo_folder() -> None:
|
143
135
|
"""Completely remove the repos folder."""
|
144
136
|
repo_folder = get_repo_folder_path()
|
145
|
-
|
137
|
+
clear_folder(repo_folder)
|
146
138
|
|
147
139
|
|
148
140
|
def get_repo_folder_path() -> str:
|
@@ -156,6 +148,15 @@ def get_repo_folder_path() -> str:
|
|
156
148
|
return repo_path
|
157
149
|
|
158
150
|
|
151
|
+
def clear_folder(folder_path: str) -> None:
|
152
|
+
"""Clear a folder on the system.
|
153
|
+
|
154
|
+
Args:
|
155
|
+
folder_path: The folder to remove.
|
156
|
+
"""
|
157
|
+
subprocess.run(['rmdir', '/s', '/q', folder_path], check=False, shell=True, capture_output=True)
|
158
|
+
|
159
|
+
|
159
160
|
def find_main_file(folder_path: str) -> str:
|
160
161
|
"""Finds the file in the given folder with the name 'main.py'.
|
161
162
|
The search checks subfolders recursively.
|
@@ -193,6 +194,9 @@ def end_job(job: Job) -> None:
|
|
193
194
|
elif isinstance(job.trigger, QueueTrigger):
|
194
195
|
db_util.set_trigger_status(job.trigger.id, TriggerStatus.IDLE)
|
195
196
|
|
197
|
+
if job.process_folder:
|
198
|
+
clear_folder(job.process_folder)
|
199
|
+
|
196
200
|
|
197
201
|
def fail_job(job: Job) -> None:
|
198
202
|
"""Mark a job as failed in the triggers table in the database.
|
@@ -205,8 +209,11 @@ def fail_job(job: Job) -> None:
|
|
205
209
|
error_msg = f"An uncaught error ocurred during the process:\n{error}"
|
206
210
|
db_util.create_log(job.trigger.process_name, LogLevel.ERROR, error_msg)
|
207
211
|
|
212
|
+
if job.process_folder:
|
213
|
+
clear_folder(job.process_folder)
|
208
214
|
|
209
|
-
|
215
|
+
|
216
|
+
def run_process(trigger: Trigger) -> Job | None:
|
210
217
|
"""Runs the process of the given trigger with the necessary inputs:
|
211
218
|
Process name
|
212
219
|
Connection string
|
@@ -224,14 +231,15 @@ def run_process(trigger: Trigger) -> subprocess.Popen | None:
|
|
224
231
|
trigger: The trigger whose process to run.
|
225
232
|
|
226
233
|
Returns:
|
227
|
-
|
234
|
+
Job: A Job object referencing the process if succesful.
|
228
235
|
"""
|
229
236
|
process_path = trigger.process_path
|
237
|
+
folder_path = None
|
230
238
|
|
231
239
|
try:
|
232
240
|
if trigger.is_git_repo:
|
233
|
-
|
234
|
-
process_path = find_main_file(
|
241
|
+
folder_path = clone_git_repo(process_path)
|
242
|
+
process_path = find_main_file(folder_path)
|
235
243
|
|
236
244
|
if not os.path.isfile(process_path):
|
237
245
|
raise ValueError(f"The process path didn't point to a file on the system. Path: '{process_path}'")
|
@@ -244,7 +252,9 @@ def run_process(trigger: Trigger) -> subprocess.Popen | None:
|
|
244
252
|
|
245
253
|
command_args = ['python', process_path, trigger.process_name, conn_string, crypto_key, trigger.process_args]
|
246
254
|
|
247
|
-
|
255
|
+
process = subprocess.Popen(command_args, stderr=subprocess.PIPE, text=True) # pylint: disable=consider-using-with
|
256
|
+
|
257
|
+
return Job(process, trigger, folder_path)
|
248
258
|
|
249
259
|
# We actually want to catch any exception here
|
250
260
|
# pylint: disable=broad-exception-caught
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: OpenOrchestrator
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.2.0
|
4
4
|
Summary: A package containing OpenOrchestrator and OpenOrchestrator Scheduler
|
5
5
|
Author-email: ITK Development <itk-rpa@mkb.aarhus.dk>
|
6
6
|
Project-URL: Homepage, https://github.com/itk-dev-rpa/OpenOrchestrator
|
@@ -6,12 +6,12 @@ OpenOrchestrator/common/crypto_util.py,sha256=Yo3WvIJnWtBJvlbvkDRu-HaReUUdaW747P
|
|
6
6
|
OpenOrchestrator/common/datetime_util.py,sha256=xNf_LORb67ohR3KfWE_owY15RqAOLJ8DfDPQlMBfsGc,527
|
7
7
|
OpenOrchestrator/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
8
|
OpenOrchestrator/database/constants.py,sha256=ik6lY6IR8EOyKEg-N70X-0U654i3nFb3u-XWhqbUbJU,2404
|
9
|
-
OpenOrchestrator/database/db_util.py,sha256=
|
9
|
+
OpenOrchestrator/database/db_util.py,sha256=VViN_V7o2zhKJcxsv-jMQmwecvXRavWgLsBKQZYm61o,27568
|
10
10
|
OpenOrchestrator/database/logs.py,sha256=h2BztjmDRhj8TACYN3LK5c9hIqn5xCs9m_LDUdYYHEk,1623
|
11
11
|
OpenOrchestrator/database/queues.py,sha256=BFCbUUbo_OOCPNCzRRxDcgoxos_LI__Ypg7t9e3qdUk,2264
|
12
12
|
OpenOrchestrator/database/triggers.py,sha256=Qq1lsSNrOYBKXnKhaD5s71YVmviaTxiD8j8kMBc76sg,4004
|
13
13
|
OpenOrchestrator/orchestrator/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
14
|
-
OpenOrchestrator/orchestrator/application.py,sha256=
|
14
|
+
OpenOrchestrator/orchestrator/application.py,sha256=Sb0rMrlFsvwkXuTLvBLqTUNqFSYjvdrAz3keiQYiUvY,3224
|
15
15
|
OpenOrchestrator/orchestrator/datetime_input.py,sha256=1EEkmKxYOQSIE6e-anbjACgbo7SL4wyuhqerdiBIg5w,2571
|
16
16
|
OpenOrchestrator/orchestrator/popups/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
17
|
OpenOrchestrator/orchestrator/popups/constant_popup.py,sha256=B6-xfEYRNNkf4dwbPgjGRuDqfKDL5pa6wUoZJ-A2l4g,3367
|
@@ -20,19 +20,19 @@ OpenOrchestrator/orchestrator/popups/generic_popups.py,sha256=wV5isJrwFGUBpDhDpu
|
|
20
20
|
OpenOrchestrator/orchestrator/popups/trigger_popup.py,sha256=Ir8Hx-DHtvCu3qm5BkG0uSRTObM9G4fpk-VOfeajelA,9684
|
21
21
|
OpenOrchestrator/orchestrator/tabs/constants_tab.py,sha256=JcRIyntrzZBh5Ugkb0QrkBrjI-g9xl2VpbeKhdT6bFM,2478
|
22
22
|
OpenOrchestrator/orchestrator/tabs/logging_tab.py,sha256=7HdXAnAMDHGC6Au8FaQ58M8i88oalBBtBAvGvdiRD_0,3527
|
23
|
-
OpenOrchestrator/orchestrator/tabs/queue_tab.py,sha256=
|
23
|
+
OpenOrchestrator/orchestrator/tabs/queue_tab.py,sha256=3JwrQUFr796uDmASDESjal1py18OT-Vq5K_VrnPlHCk,5169
|
24
24
|
OpenOrchestrator/orchestrator/tabs/settings_tab.py,sha256=xBMBdgrTxehmbuAk-H3QfEP_zdILzJ3sIgMCii7qlQg,845
|
25
|
-
OpenOrchestrator/orchestrator/tabs/trigger_tab.py,sha256=
|
25
|
+
OpenOrchestrator/orchestrator/tabs/trigger_tab.py,sha256=gRwLINuf4wQcFieNZL1grlc5qmPOqGRAI1-TS1za_5Q,4047
|
26
26
|
OpenOrchestrator/orchestrator_connection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
27
27
|
OpenOrchestrator/orchestrator_connection/connection.py,sha256=DU552EigOu2xzM3SjY4766BXrDEnDC2jC4Jjy0-9OrU,8706
|
28
28
|
OpenOrchestrator/scheduler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
29
|
-
OpenOrchestrator/scheduler/application.py,sha256=
|
29
|
+
OpenOrchestrator/scheduler/application.py,sha256=vjDzW8x0MwS9giFI6UOlhtFqUPHKbsRnrb6-HY8jWOI,1620
|
30
30
|
OpenOrchestrator/scheduler/connection_frame.py,sha256=I1Qooso_iqkNhvztQvFgjlC89Lvfqx0s5B6olATqa98,3369
|
31
|
-
OpenOrchestrator/scheduler/run_tab.py,sha256=
|
32
|
-
OpenOrchestrator/scheduler/runner.py,sha256=
|
31
|
+
OpenOrchestrator/scheduler/run_tab.py,sha256=QP-hoZEJAI5A-T7kV1lFCftpTm_e_R3T8I2Fg9BHxnA,5779
|
32
|
+
OpenOrchestrator/scheduler/runner.py,sha256=0lI-Xpv4Co617ZvTrRm9pCAZP1-aNg0P-Vy1c1oy7cM,8170
|
33
33
|
OpenOrchestrator/scheduler/settings_tab.py,sha256=AQxt5HxPn4sLfj-6GwyAQ8ffJ35D0PHLBVoi8W3tu2A,613
|
34
|
-
OpenOrchestrator-1.
|
35
|
-
OpenOrchestrator-1.
|
36
|
-
OpenOrchestrator-1.
|
37
|
-
OpenOrchestrator-1.
|
38
|
-
OpenOrchestrator-1.
|
34
|
+
OpenOrchestrator-1.2.0.dist-info/LICENSE,sha256=4-Kjm-gkbiOLCBYMzsVJZEepdsm2vk8QesNOASvi9mg,1068
|
35
|
+
OpenOrchestrator-1.2.0.dist-info/METADATA,sha256=Y0hvXWs-UDhtwmJ4X9YTSGeZwqmxykiulkZleWTBwXw,1938
|
36
|
+
OpenOrchestrator-1.2.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
37
|
+
OpenOrchestrator-1.2.0.dist-info/top_level.txt,sha256=2btKMQESHuRC_ICbCjHTHH_-us2G7CyeskeaSTTL07Y,17
|
38
|
+
OpenOrchestrator-1.2.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|