OAPI: add endpoint for fetching the tasks of a job
Add `fetchJobTasks` operation to the Jobs API. This returns a summary of each of the job's tasks, suitable for display in a task list view. The actually used fields may need tweaking once we actually have a task list view, but at least the functionality is there.
This commit is contained in:
parent
e399b14e66
commit
992fc38604
@ -10,7 +10,7 @@
|
||||
"""
|
||||
|
||||
|
||||
__version__ = "b699647e-dirty"
|
||||
__version__ = "e399b14e-dirty"
|
||||
|
||||
# import ApiClient
|
||||
from flamenco.manager.api_client import ApiClient
|
||||
|
@ -26,6 +26,7 @@ from flamenco.manager.model.available_job_types import AvailableJobTypes
|
||||
from flamenco.manager.model.error import Error
|
||||
from flamenco.manager.model.job import Job
|
||||
from flamenco.manager.model.job_status_change import JobStatusChange
|
||||
from flamenco.manager.model.job_tasks_summary import JobTasksSummary
|
||||
from flamenco.manager.model.jobs_query import JobsQuery
|
||||
from flamenco.manager.model.jobs_query_result import JobsQueryResult
|
||||
from flamenco.manager.model.submitted_job import SubmittedJob
|
||||
@ -91,6 +92,55 @@ class JobsApi(object):
|
||||
},
|
||||
api_client=api_client
|
||||
)
|
||||
self.fetch_job_tasks_endpoint = _Endpoint(
|
||||
settings={
|
||||
'response_type': (JobTasksSummary,),
|
||||
'auth': [],
|
||||
'endpoint_path': '/api/jobs/{job_id}/tasks',
|
||||
'operation_id': 'fetch_job_tasks',
|
||||
'http_method': 'GET',
|
||||
'servers': None,
|
||||
},
|
||||
params_map={
|
||||
'all': [
|
||||
'job_id',
|
||||
],
|
||||
'required': [
|
||||
'job_id',
|
||||
],
|
||||
'nullable': [
|
||||
],
|
||||
'enum': [
|
||||
],
|
||||
'validation': [
|
||||
]
|
||||
},
|
||||
root_map={
|
||||
'validations': {
|
||||
},
|
||||
'allowed_values': {
|
||||
},
|
||||
'openapi_types': {
|
||||
'job_id':
|
||||
(str,),
|
||||
},
|
||||
'attribute_map': {
|
||||
'job_id': 'job_id',
|
||||
},
|
||||
'location_map': {
|
||||
'job_id': 'path',
|
||||
},
|
||||
'collection_format_map': {
|
||||
}
|
||||
},
|
||||
headers_map={
|
||||
'accept': [
|
||||
'application/json'
|
||||
],
|
||||
'content_type': [],
|
||||
},
|
||||
api_client=api_client
|
||||
)
|
||||
self.get_job_type_endpoint = _Endpoint(
|
||||
settings={
|
||||
'response_type': (AvailableJobType,),
|
||||
@ -416,6 +466,83 @@ class JobsApi(object):
|
||||
job_id
|
||||
return self.fetch_job_endpoint.call_with_http_info(**kwargs)
|
||||
|
||||
def fetch_job_tasks(
|
||||
self,
|
||||
job_id,
|
||||
**kwargs
|
||||
):
|
||||
"""Fetch a summary of all tasks of the given job. # noqa: E501
|
||||
|
||||
This method makes a synchronous HTTP request by default. To make an
|
||||
asynchronous HTTP request, please pass async_req=True
|
||||
|
||||
>>> thread = api.fetch_job_tasks(job_id, async_req=True)
|
||||
>>> result = thread.get()
|
||||
|
||||
Args:
|
||||
job_id (str):
|
||||
|
||||
Keyword Args:
|
||||
_return_http_data_only (bool): response data without head status
|
||||
code and headers. Default is True.
|
||||
_preload_content (bool): if False, the urllib3.HTTPResponse object
|
||||
will be returned without reading/decoding response data.
|
||||
Default is True.
|
||||
_request_timeout (int/float/tuple): timeout setting for this request. If
|
||||
one number provided, it will be total request timeout. It can also
|
||||
be a pair (tuple) of (connection, read) timeouts.
|
||||
Default is None.
|
||||
_check_input_type (bool): specifies if type checking
|
||||
should be done one the data sent to the server.
|
||||
Default is True.
|
||||
_check_return_type (bool): specifies if type checking
|
||||
should be done one the data received from the server.
|
||||
Default is True.
|
||||
_spec_property_naming (bool): True if the variable names in the input data
|
||||
are serialized names, as specified in the OpenAPI document.
|
||||
False if the variable names in the input data
|
||||
are pythonic names, e.g. snake case (default)
|
||||
_content_type (str/None): force body content-type.
|
||||
Default is None and content-type will be predicted by allowed
|
||||
content-types and body.
|
||||
_host_index (int/None): specifies the index of the server
|
||||
that we want to use.
|
||||
Default is read from the configuration.
|
||||
async_req (bool): execute request asynchronously
|
||||
|
||||
Returns:
|
||||
JobTasksSummary
|
||||
If the method is called asynchronously, returns the request
|
||||
thread.
|
||||
"""
|
||||
kwargs['async_req'] = kwargs.get(
|
||||
'async_req', False
|
||||
)
|
||||
kwargs['_return_http_data_only'] = kwargs.get(
|
||||
'_return_http_data_only', True
|
||||
)
|
||||
kwargs['_preload_content'] = kwargs.get(
|
||||
'_preload_content', True
|
||||
)
|
||||
kwargs['_request_timeout'] = kwargs.get(
|
||||
'_request_timeout', None
|
||||
)
|
||||
kwargs['_check_input_type'] = kwargs.get(
|
||||
'_check_input_type', True
|
||||
)
|
||||
kwargs['_check_return_type'] = kwargs.get(
|
||||
'_check_return_type', True
|
||||
)
|
||||
kwargs['_spec_property_naming'] = kwargs.get(
|
||||
'_spec_property_naming', False
|
||||
)
|
||||
kwargs['_content_type'] = kwargs.get(
|
||||
'_content_type')
|
||||
kwargs['_host_index'] = kwargs.get('_host_index')
|
||||
kwargs['job_id'] = \
|
||||
job_id
|
||||
return self.fetch_job_tasks_endpoint.call_with_http_info(**kwargs)
|
||||
|
||||
def get_job_type(
|
||||
self,
|
||||
type_name,
|
||||
|
@ -76,7 +76,7 @@ class ApiClient(object):
|
||||
self.default_headers[header_name] = header_value
|
||||
self.cookie = cookie
|
||||
# Set default User-Agent.
|
||||
self.user_agent = 'Flamenco/b699647e-dirty (Blender add-on)'
|
||||
self.user_agent = 'Flamenco/e399b14e-dirty (Blender add-on)'
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
@ -404,7 +404,7 @@ conf = flamenco.manager.Configuration(
|
||||
"OS: {env}\n"\
|
||||
"Python Version: {pyversion}\n"\
|
||||
"Version of the API: 1.0.0\n"\
|
||||
"SDK Package Version: b699647e-dirty".\
|
||||
"SDK Package Version: e399b14e-dirty".\
|
||||
format(env=sys.platform, pyversion=sys.version)
|
||||
|
||||
def get_host_settings(self):
|
||||
|
@ -8,7 +8,7 @@ Name | Type | Description | Notes
|
||||
**type** | **str** | |
|
||||
**id** | **str** | UUID of the Job |
|
||||
**created** | **datetime** | Creation timestamp |
|
||||
**updated** | **datetime** | Creation timestamp |
|
||||
**updated** | **datetime** | Timestamp of last update. |
|
||||
**status** | [**JobStatus**](JobStatus.md) | |
|
||||
**activity** | **str** | Description of the last activity on this job. |
|
||||
**priority** | **int** | | defaults to 50
|
||||
|
@ -6,7 +6,7 @@ Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**id** | **str** | UUID of the Job |
|
||||
**created** | **datetime** | Creation timestamp |
|
||||
**updated** | **datetime** | Creation timestamp |
|
||||
**updated** | **datetime** | Timestamp of last update. |
|
||||
**status** | [**JobStatus**](JobStatus.md) | |
|
||||
**activity** | **str** | Description of the last activity on this job. |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
13
addon/flamenco/manager/docs/JobTasksSummary.md
Normal file
13
addon/flamenco/manager/docs/JobTasksSummary.md
Normal file
@ -0,0 +1,13 @@
|
||||
# JobTasksSummary
|
||||
|
||||
Simplified list of tasks of a job. Contains all tasks, but not all info of each task.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**tasks** | [**[TaskSummary]**](TaskSummary.md) | | [optional]
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
@ -5,6 +5,7 @@ All URIs are relative to *http://localhost*
|
||||
Method | HTTP request | Description
|
||||
------------- | ------------- | -------------
|
||||
[**fetch_job**](JobsApi.md#fetch_job) | **GET** /api/jobs/{job_id} | Fetch info about the job.
|
||||
[**fetch_job_tasks**](JobsApi.md#fetch_job_tasks) | **GET** /api/jobs/{job_id}/tasks | Fetch a summary of all tasks of the given job.
|
||||
[**get_job_type**](JobsApi.md#get_job_type) | **GET** /api/jobs/type/{typeName} | Get single job type and its parameters.
|
||||
[**get_job_types**](JobsApi.md#get_job_types) | **GET** /api/jobs/types | Get list of job types and their parameters.
|
||||
[**query_jobs**](JobsApi.md#query_jobs) | **POST** /api/jobs/query | Fetch list of jobs.
|
||||
@ -77,6 +78,73 @@ No authorization required
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **fetch_job_tasks**
|
||||
> JobTasksSummary fetch_job_tasks(job_id)
|
||||
|
||||
Fetch a summary of all tasks of the given job.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```python
|
||||
import time
|
||||
import flamenco.manager
|
||||
from flamenco.manager.api import jobs_api
|
||||
from flamenco.manager.model.error import Error
|
||||
from flamenco.manager.model.job_tasks_summary import JobTasksSummary
|
||||
from pprint import pprint
|
||||
# Defining the host is optional and defaults to http://localhost
|
||||
# See configuration.py for a list of all supported configuration parameters.
|
||||
configuration = flamenco.manager.Configuration(
|
||||
host = "http://localhost"
|
||||
)
|
||||
|
||||
|
||||
# Enter a context with an instance of the API client
|
||||
with flamenco.manager.ApiClient() as api_client:
|
||||
# Create an instance of the API class
|
||||
api_instance = jobs_api.JobsApi(api_client)
|
||||
job_id = "job_id_example" # str |
|
||||
|
||||
# example passing only required values which don't have defaults set
|
||||
try:
|
||||
# Fetch a summary of all tasks of the given job.
|
||||
api_response = api_instance.fetch_job_tasks(job_id)
|
||||
pprint(api_response)
|
||||
except flamenco.manager.ApiException as e:
|
||||
print("Exception when calling JobsApi->fetch_job_tasks: %s\n" % e)
|
||||
```
|
||||
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**job_id** | **str**| |
|
||||
|
||||
### Return type
|
||||
|
||||
[**JobTasksSummary**](JobTasksSummary.md)
|
||||
|
||||
### Authorization
|
||||
|
||||
No authorization required
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: Not defined
|
||||
- **Accept**: application/json
|
||||
|
||||
|
||||
### HTTP response details
|
||||
|
||||
| Status code | Description | Response headers |
|
||||
|-------------|-------------|------------------|
|
||||
**200** | Get summaries of the tasks of this job. | - |
|
||||
**0** | Unexpected error. | - |
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **get_job_type**
|
||||
> AvailableJobType get_job_type(type_name)
|
||||
|
||||
|
18
addon/flamenco/manager/docs/TaskSummary.md
Normal file
18
addon/flamenco/manager/docs/TaskSummary.md
Normal file
@ -0,0 +1,18 @@
|
||||
# TaskSummary
|
||||
|
||||
Just enough information about the task to show in the job's task list.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**id** | **str** | |
|
||||
**name** | **str** | |
|
||||
**status** | [**TaskStatus**](TaskStatus.md) | |
|
||||
**priority** | **int** | |
|
||||
**task_type** | **str** | |
|
||||
**updated** | **datetime** | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
@ -139,7 +139,7 @@ class Job(ModelComposed):
|
||||
priority (int): defaults to 50 # noqa: E501
|
||||
id (str): UUID of the Job
|
||||
created (datetime): Creation timestamp
|
||||
updated (datetime): Creation timestamp
|
||||
updated (datetime): Timestamp of last update.
|
||||
status (JobStatus):
|
||||
activity (str): Description of the last activity on this job.
|
||||
_check_type (bool): if True, values for parameters in openapi_types
|
||||
@ -249,7 +249,7 @@ class Job(ModelComposed):
|
||||
priority (int): defaults to 50 # noqa: E501
|
||||
id (str): UUID of the Job
|
||||
created (datetime): Creation timestamp
|
||||
updated (datetime): Creation timestamp
|
||||
updated (datetime): Timestamp of last update.
|
||||
status (JobStatus):
|
||||
activity (str): Description of the last activity on this job.
|
||||
_check_type (bool): if True, values for parameters in openapi_types
|
||||
|
@ -120,7 +120,7 @@ class JobAllOf(ModelNormal):
|
||||
Args:
|
||||
id (str): UUID of the Job
|
||||
created (datetime): Creation timestamp
|
||||
updated (datetime): Creation timestamp
|
||||
updated (datetime): Timestamp of last update.
|
||||
status (JobStatus):
|
||||
activity (str): Description of the last activity on this job.
|
||||
|
||||
@ -213,7 +213,7 @@ class JobAllOf(ModelNormal):
|
||||
Args:
|
||||
id (str): UUID of the Job
|
||||
created (datetime): Creation timestamp
|
||||
updated (datetime): Creation timestamp
|
||||
updated (datetime): Timestamp of last update.
|
||||
status (JobStatus):
|
||||
activity (str): Description of the last activity on this job.
|
||||
|
||||
|
261
addon/flamenco/manager/model/job_tasks_summary.py
Normal file
261
addon/flamenco/manager/model/job_tasks_summary.py
Normal file
@ -0,0 +1,261 @@
|
||||
"""
|
||||
Flamenco manager
|
||||
|
||||
Render Farm manager API # noqa: E501
|
||||
|
||||
The version of the OpenAPI document: 1.0.0
|
||||
Generated by: https://openapi-generator.tech
|
||||
"""
|
||||
|
||||
|
||||
import re # noqa: F401
|
||||
import sys # noqa: F401
|
||||
|
||||
from flamenco.manager.model_utils import ( # noqa: F401
|
||||
ApiTypeError,
|
||||
ModelComposed,
|
||||
ModelNormal,
|
||||
ModelSimple,
|
||||
cached_property,
|
||||
change_keys_js_to_python,
|
||||
convert_js_args_to_python_args,
|
||||
date,
|
||||
datetime,
|
||||
file_type,
|
||||
none_type,
|
||||
validate_get_composed_info,
|
||||
OpenApiModel
|
||||
)
|
||||
from flamenco.manager.exceptions import ApiAttributeError
|
||||
|
||||
|
||||
def lazy_import():
|
||||
from flamenco.manager.model.task_summary import TaskSummary
|
||||
globals()['TaskSummary'] = TaskSummary
|
||||
|
||||
|
||||
class JobTasksSummary(ModelNormal):
|
||||
"""NOTE: This class is auto generated by OpenAPI Generator.
|
||||
Ref: https://openapi-generator.tech
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
Attributes:
|
||||
allowed_values (dict): The key is the tuple path to the attribute
|
||||
and the for var_name this is (var_name,). The value is a dict
|
||||
with a capitalized key describing the allowed value and an allowed
|
||||
value. These dicts store the allowed enum values.
|
||||
attribute_map (dict): The key is attribute name
|
||||
and the value is json key in definition.
|
||||
discriminator_value_class_map (dict): A dict to go from the discriminator
|
||||
variable value to the discriminator class name.
|
||||
validations (dict): The key is the tuple path to the attribute
|
||||
and the for var_name this is (var_name,). The value is a dict
|
||||
that stores validations for max_length, min_length, max_items,
|
||||
min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum,
|
||||
inclusive_minimum, and regex.
|
||||
additional_properties_type (tuple): A tuple of classes accepted
|
||||
as additional properties values.
|
||||
"""
|
||||
|
||||
allowed_values = {
|
||||
}
|
||||
|
||||
validations = {
|
||||
}
|
||||
|
||||
@cached_property
|
||||
def additional_properties_type():
|
||||
"""
|
||||
This must be a method because a model may have properties that are
|
||||
of type self, this must run after the class is loaded
|
||||
"""
|
||||
lazy_import()
|
||||
return (bool, date, datetime, dict, float, int, list, str, none_type,) # noqa: E501
|
||||
|
||||
_nullable = False
|
||||
|
||||
@cached_property
|
||||
def openapi_types():
|
||||
"""
|
||||
This must be a method because a model may have properties that are
|
||||
of type self, this must run after the class is loaded
|
||||
|
||||
Returns
|
||||
openapi_types (dict): The key is attribute name
|
||||
and the value is attribute type.
|
||||
"""
|
||||
lazy_import()
|
||||
return {
|
||||
'tasks': ([TaskSummary],), # noqa: E501
|
||||
}
|
||||
|
||||
@cached_property
|
||||
def discriminator():
|
||||
return None
|
||||
|
||||
|
||||
attribute_map = {
|
||||
'tasks': 'tasks', # noqa: E501
|
||||
}
|
||||
|
||||
read_only_vars = {
|
||||
}
|
||||
|
||||
_composed_schemas = {}
|
||||
|
||||
@classmethod
|
||||
@convert_js_args_to_python_args
|
||||
def _from_openapi_data(cls, *args, **kwargs): # noqa: E501
|
||||
"""JobTasksSummary - a model defined in OpenAPI
|
||||
|
||||
Keyword Args:
|
||||
_check_type (bool): if True, values for parameters in openapi_types
|
||||
will be type checked and a TypeError will be
|
||||
raised if the wrong type is input.
|
||||
Defaults to True
|
||||
_path_to_item (tuple/list): This is a list of keys or values to
|
||||
drill down to the model in received_data
|
||||
when deserializing a response
|
||||
_spec_property_naming (bool): True if the variable names in the input data
|
||||
are serialized names, as specified in the OpenAPI document.
|
||||
False if the variable names in the input data
|
||||
are pythonic names, e.g. snake case (default)
|
||||
_configuration (Configuration): the instance to use when
|
||||
deserializing a file_type parameter.
|
||||
If passed, type conversion is attempted
|
||||
If omitted no type conversion is done.
|
||||
_visited_composed_classes (tuple): This stores a tuple of
|
||||
classes that we have traveled through so that
|
||||
if we see that class again we will not use its
|
||||
discriminator again.
|
||||
When traveling through a discriminator, the
|
||||
composed schema that is
|
||||
is traveled through is added to this set.
|
||||
For example if Animal has a discriminator
|
||||
petType and we pass in "Dog", and the class Dog
|
||||
allOf includes Animal, we move through Animal
|
||||
once using the discriminator, and pick Dog.
|
||||
Then in Dog, we will make an instance of the
|
||||
Animal class but this time we won't travel
|
||||
through its discriminator because we passed in
|
||||
_visited_composed_classes = (Animal,)
|
||||
tasks ([TaskSummary]): [optional] # noqa: E501
|
||||
"""
|
||||
|
||||
_check_type = kwargs.pop('_check_type', True)
|
||||
_spec_property_naming = kwargs.pop('_spec_property_naming', False)
|
||||
_path_to_item = kwargs.pop('_path_to_item', ())
|
||||
_configuration = kwargs.pop('_configuration', None)
|
||||
_visited_composed_classes = kwargs.pop('_visited_composed_classes', ())
|
||||
|
||||
self = super(OpenApiModel, cls).__new__(cls)
|
||||
|
||||
if args:
|
||||
raise ApiTypeError(
|
||||
"Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % (
|
||||
args,
|
||||
self.__class__.__name__,
|
||||
),
|
||||
path_to_item=_path_to_item,
|
||||
valid_classes=(self.__class__,),
|
||||
)
|
||||
|
||||
self._data_store = {}
|
||||
self._check_type = _check_type
|
||||
self._spec_property_naming = _spec_property_naming
|
||||
self._path_to_item = _path_to_item
|
||||
self._configuration = _configuration
|
||||
self._visited_composed_classes = _visited_composed_classes + (self.__class__,)
|
||||
|
||||
for var_name, var_value in kwargs.items():
|
||||
if var_name not in self.attribute_map and \
|
||||
self._configuration is not None and \
|
||||
self._configuration.discard_unknown_keys and \
|
||||
self.additional_properties_type is None:
|
||||
# discard variable.
|
||||
continue
|
||||
setattr(self, var_name, var_value)
|
||||
return self
|
||||
|
||||
required_properties = set([
|
||||
'_data_store',
|
||||
'_check_type',
|
||||
'_spec_property_naming',
|
||||
'_path_to_item',
|
||||
'_configuration',
|
||||
'_visited_composed_classes',
|
||||
])
|
||||
|
||||
@convert_js_args_to_python_args
|
||||
def __init__(self, *args, **kwargs): # noqa: E501
|
||||
"""JobTasksSummary - a model defined in OpenAPI
|
||||
|
||||
Keyword Args:
|
||||
_check_type (bool): if True, values for parameters in openapi_types
|
||||
will be type checked and a TypeError will be
|
||||
raised if the wrong type is input.
|
||||
Defaults to True
|
||||
_path_to_item (tuple/list): This is a list of keys or values to
|
||||
drill down to the model in received_data
|
||||
when deserializing a response
|
||||
_spec_property_naming (bool): True if the variable names in the input data
|
||||
are serialized names, as specified in the OpenAPI document.
|
||||
False if the variable names in the input data
|
||||
are pythonic names, e.g. snake case (default)
|
||||
_configuration (Configuration): the instance to use when
|
||||
deserializing a file_type parameter.
|
||||
If passed, type conversion is attempted
|
||||
If omitted no type conversion is done.
|
||||
_visited_composed_classes (tuple): This stores a tuple of
|
||||
classes that we have traveled through so that
|
||||
if we see that class again we will not use its
|
||||
discriminator again.
|
||||
When traveling through a discriminator, the
|
||||
composed schema that is
|
||||
is traveled through is added to this set.
|
||||
For example if Animal has a discriminator
|
||||
petType and we pass in "Dog", and the class Dog
|
||||
allOf includes Animal, we move through Animal
|
||||
once using the discriminator, and pick Dog.
|
||||
Then in Dog, we will make an instance of the
|
||||
Animal class but this time we won't travel
|
||||
through its discriminator because we passed in
|
||||
_visited_composed_classes = (Animal,)
|
||||
tasks ([TaskSummary]): [optional] # noqa: E501
|
||||
"""
|
||||
|
||||
_check_type = kwargs.pop('_check_type', True)
|
||||
_spec_property_naming = kwargs.pop('_spec_property_naming', False)
|
||||
_path_to_item = kwargs.pop('_path_to_item', ())
|
||||
_configuration = kwargs.pop('_configuration', None)
|
||||
_visited_composed_classes = kwargs.pop('_visited_composed_classes', ())
|
||||
|
||||
if args:
|
||||
raise ApiTypeError(
|
||||
"Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % (
|
||||
args,
|
||||
self.__class__.__name__,
|
||||
),
|
||||
path_to_item=_path_to_item,
|
||||
valid_classes=(self.__class__,),
|
||||
)
|
||||
|
||||
self._data_store = {}
|
||||
self._check_type = _check_type
|
||||
self._spec_property_naming = _spec_property_naming
|
||||
self._path_to_item = _path_to_item
|
||||
self._configuration = _configuration
|
||||
self._visited_composed_classes = _visited_composed_classes + (self.__class__,)
|
||||
|
||||
for var_name, var_value in kwargs.items():
|
||||
if var_name not in self.attribute_map and \
|
||||
self._configuration is not None and \
|
||||
self._configuration.discard_unknown_keys and \
|
||||
self.additional_properties_type is None:
|
||||
# discard variable.
|
||||
continue
|
||||
setattr(self, var_name, var_value)
|
||||
if var_name in self.read_only_vars:
|
||||
raise ApiAttributeError(f"`{var_name}` is a read-only attribute. Use `from_openapi_data` to instantiate "
|
||||
f"class with read only attributes.")
|
297
addon/flamenco/manager/model/task_summary.py
Normal file
297
addon/flamenco/manager/model/task_summary.py
Normal file
@ -0,0 +1,297 @@
|
||||
"""
|
||||
Flamenco manager
|
||||
|
||||
Render Farm manager API # noqa: E501
|
||||
|
||||
The version of the OpenAPI document: 1.0.0
|
||||
Generated by: https://openapi-generator.tech
|
||||
"""
|
||||
|
||||
|
||||
import re # noqa: F401
|
||||
import sys # noqa: F401
|
||||
|
||||
from flamenco.manager.model_utils import ( # noqa: F401
|
||||
ApiTypeError,
|
||||
ModelComposed,
|
||||
ModelNormal,
|
||||
ModelSimple,
|
||||
cached_property,
|
||||
change_keys_js_to_python,
|
||||
convert_js_args_to_python_args,
|
||||
date,
|
||||
datetime,
|
||||
file_type,
|
||||
none_type,
|
||||
validate_get_composed_info,
|
||||
OpenApiModel
|
||||
)
|
||||
from flamenco.manager.exceptions import ApiAttributeError
|
||||
|
||||
|
||||
def lazy_import():
|
||||
from flamenco.manager.model.task_status import TaskStatus
|
||||
globals()['TaskStatus'] = TaskStatus
|
||||
|
||||
|
||||
class TaskSummary(ModelNormal):
|
||||
"""NOTE: This class is auto generated by OpenAPI Generator.
|
||||
Ref: https://openapi-generator.tech
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
Attributes:
|
||||
allowed_values (dict): The key is the tuple path to the attribute
|
||||
and the for var_name this is (var_name,). The value is a dict
|
||||
with a capitalized key describing the allowed value and an allowed
|
||||
value. These dicts store the allowed enum values.
|
||||
attribute_map (dict): The key is attribute name
|
||||
and the value is json key in definition.
|
||||
discriminator_value_class_map (dict): A dict to go from the discriminator
|
||||
variable value to the discriminator class name.
|
||||
validations (dict): The key is the tuple path to the attribute
|
||||
and the for var_name this is (var_name,). The value is a dict
|
||||
that stores validations for max_length, min_length, max_items,
|
||||
min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum,
|
||||
inclusive_minimum, and regex.
|
||||
additional_properties_type (tuple): A tuple of classes accepted
|
||||
as additional properties values.
|
||||
"""
|
||||
|
||||
allowed_values = {
|
||||
}
|
||||
|
||||
validations = {
|
||||
}
|
||||
|
||||
@cached_property
|
||||
def additional_properties_type():
|
||||
"""
|
||||
This must be a method because a model may have properties that are
|
||||
of type self, this must run after the class is loaded
|
||||
"""
|
||||
lazy_import()
|
||||
return (bool, date, datetime, dict, float, int, list, str, none_type,) # noqa: E501
|
||||
|
||||
_nullable = False
|
||||
|
||||
@cached_property
|
||||
def openapi_types():
|
||||
"""
|
||||
This must be a method because a model may have properties that are
|
||||
of type self, this must run after the class is loaded
|
||||
|
||||
Returns
|
||||
openapi_types (dict): The key is attribute name
|
||||
and the value is attribute type.
|
||||
"""
|
||||
lazy_import()
|
||||
return {
|
||||
'id': (str,), # noqa: E501
|
||||
'name': (str,), # noqa: E501
|
||||
'status': (TaskStatus,), # noqa: E501
|
||||
'priority': (int,), # noqa: E501
|
||||
'task_type': (str,), # noqa: E501
|
||||
'updated': (datetime,), # noqa: E501
|
||||
}
|
||||
|
||||
@cached_property
|
||||
def discriminator():
|
||||
return None
|
||||
|
||||
|
||||
attribute_map = {
|
||||
'id': 'id', # noqa: E501
|
||||
'name': 'name', # noqa: E501
|
||||
'status': 'status', # noqa: E501
|
||||
'priority': 'priority', # noqa: E501
|
||||
'task_type': 'task_type', # noqa: E501
|
||||
'updated': 'updated', # noqa: E501
|
||||
}
|
||||
|
||||
read_only_vars = {
|
||||
}
|
||||
|
||||
_composed_schemas = {}
|
||||
|
||||
@classmethod
|
||||
@convert_js_args_to_python_args
|
||||
def _from_openapi_data(cls, id, name, status, priority, task_type, updated, *args, **kwargs): # noqa: E501
|
||||
"""TaskSummary - a model defined in OpenAPI
|
||||
|
||||
Args:
|
||||
id (str):
|
||||
name (str):
|
||||
status (TaskStatus):
|
||||
priority (int):
|
||||
task_type (str):
|
||||
updated (datetime):
|
||||
|
||||
Keyword Args:
|
||||
_check_type (bool): if True, values for parameters in openapi_types
|
||||
will be type checked and a TypeError will be
|
||||
raised if the wrong type is input.
|
||||
Defaults to True
|
||||
_path_to_item (tuple/list): This is a list of keys or values to
|
||||
drill down to the model in received_data
|
||||
when deserializing a response
|
||||
_spec_property_naming (bool): True if the variable names in the input data
|
||||
are serialized names, as specified in the OpenAPI document.
|
||||
False if the variable names in the input data
|
||||
are pythonic names, e.g. snake case (default)
|
||||
_configuration (Configuration): the instance to use when
|
||||
deserializing a file_type parameter.
|
||||
If passed, type conversion is attempted
|
||||
If omitted no type conversion is done.
|
||||
_visited_composed_classes (tuple): This stores a tuple of
|
||||
classes that we have traveled through so that
|
||||
if we see that class again we will not use its
|
||||
discriminator again.
|
||||
When traveling through a discriminator, the
|
||||
composed schema that is
|
||||
is traveled through is added to this set.
|
||||
For example if Animal has a discriminator
|
||||
petType and we pass in "Dog", and the class Dog
|
||||
allOf includes Animal, we move through Animal
|
||||
once using the discriminator, and pick Dog.
|
||||
Then in Dog, we will make an instance of the
|
||||
Animal class but this time we won't travel
|
||||
through its discriminator because we passed in
|
||||
_visited_composed_classes = (Animal,)
|
||||
"""
|
||||
|
||||
_check_type = kwargs.pop('_check_type', True)
|
||||
_spec_property_naming = kwargs.pop('_spec_property_naming', False)
|
||||
_path_to_item = kwargs.pop('_path_to_item', ())
|
||||
_configuration = kwargs.pop('_configuration', None)
|
||||
_visited_composed_classes = kwargs.pop('_visited_composed_classes', ())
|
||||
|
||||
self = super(OpenApiModel, cls).__new__(cls)
|
||||
|
||||
if args:
|
||||
raise ApiTypeError(
|
||||
"Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % (
|
||||
args,
|
||||
self.__class__.__name__,
|
||||
),
|
||||
path_to_item=_path_to_item,
|
||||
valid_classes=(self.__class__,),
|
||||
)
|
||||
|
||||
self._data_store = {}
|
||||
self._check_type = _check_type
|
||||
self._spec_property_naming = _spec_property_naming
|
||||
self._path_to_item = _path_to_item
|
||||
self._configuration = _configuration
|
||||
self._visited_composed_classes = _visited_composed_classes + (self.__class__,)
|
||||
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.status = status
|
||||
self.priority = priority
|
||||
self.task_type = task_type
|
||||
self.updated = updated
|
||||
for var_name, var_value in kwargs.items():
|
||||
if var_name not in self.attribute_map and \
|
||||
self._configuration is not None and \
|
||||
self._configuration.discard_unknown_keys and \
|
||||
self.additional_properties_type is None:
|
||||
# discard variable.
|
||||
continue
|
||||
setattr(self, var_name, var_value)
|
||||
return self
|
||||
|
||||
required_properties = set([
|
||||
'_data_store',
|
||||
'_check_type',
|
||||
'_spec_property_naming',
|
||||
'_path_to_item',
|
||||
'_configuration',
|
||||
'_visited_composed_classes',
|
||||
])
|
||||
|
||||
@convert_js_args_to_python_args
|
||||
def __init__(self, id, name, status, priority, task_type, updated, *args, **kwargs): # noqa: E501
|
||||
"""TaskSummary - a model defined in OpenAPI
|
||||
|
||||
Args:
|
||||
id (str):
|
||||
name (str):
|
||||
status (TaskStatus):
|
||||
priority (int):
|
||||
task_type (str):
|
||||
updated (datetime):
|
||||
|
||||
Keyword Args:
|
||||
_check_type (bool): if True, values for parameters in openapi_types
|
||||
will be type checked and a TypeError will be
|
||||
raised if the wrong type is input.
|
||||
Defaults to True
|
||||
_path_to_item (tuple/list): This is a list of keys or values to
|
||||
drill down to the model in received_data
|
||||
when deserializing a response
|
||||
_spec_property_naming (bool): True if the variable names in the input data
|
||||
are serialized names, as specified in the OpenAPI document.
|
||||
False if the variable names in the input data
|
||||
are pythonic names, e.g. snake case (default)
|
||||
_configuration (Configuration): the instance to use when
|
||||
deserializing a file_type parameter.
|
||||
If passed, type conversion is attempted
|
||||
If omitted no type conversion is done.
|
||||
_visited_composed_classes (tuple): This stores a tuple of
|
||||
classes that we have traveled through so that
|
||||
if we see that class again we will not use its
|
||||
discriminator again.
|
||||
When traveling through a discriminator, the
|
||||
composed schema that is
|
||||
is traveled through is added to this set.
|
||||
For example if Animal has a discriminator
|
||||
petType and we pass in "Dog", and the class Dog
|
||||
allOf includes Animal, we move through Animal
|
||||
once using the discriminator, and pick Dog.
|
||||
Then in Dog, we will make an instance of the
|
||||
Animal class but this time we won't travel
|
||||
through its discriminator because we passed in
|
||||
_visited_composed_classes = (Animal,)
|
||||
"""
|
||||
|
||||
_check_type = kwargs.pop('_check_type', True)
|
||||
_spec_property_naming = kwargs.pop('_spec_property_naming', False)
|
||||
_path_to_item = kwargs.pop('_path_to_item', ())
|
||||
_configuration = kwargs.pop('_configuration', None)
|
||||
_visited_composed_classes = kwargs.pop('_visited_composed_classes', ())
|
||||
|
||||
if args:
|
||||
raise ApiTypeError(
|
||||
"Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % (
|
||||
args,
|
||||
self.__class__.__name__,
|
||||
),
|
||||
path_to_item=_path_to_item,
|
||||
valid_classes=(self.__class__,),
|
||||
)
|
||||
|
||||
self._data_store = {}
|
||||
self._check_type = _check_type
|
||||
self._spec_property_naming = _spec_property_naming
|
||||
self._path_to_item = _path_to_item
|
||||
self._configuration = _configuration
|
||||
self._visited_composed_classes = _visited_composed_classes + (self.__class__,)
|
||||
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.status = status
|
||||
self.priority = priority
|
||||
self.task_type = task_type
|
||||
self.updated = updated
|
||||
for var_name, var_value in kwargs.items():
|
||||
if var_name not in self.attribute_map and \
|
||||
self._configuration is not None and \
|
||||
self._configuration.discard_unknown_keys and \
|
||||
self.additional_properties_type is None:
|
||||
# discard variable.
|
||||
continue
|
||||
setattr(self, var_name, var_value)
|
||||
if var_name in self.read_only_vars:
|
||||
raise ApiAttributeError(f"`{var_name}` is a read-only attribute. Use `from_openapi_data` to instantiate "
|
||||
f"class with read only attributes.")
|
@ -24,6 +24,7 @@ from flamenco.manager.model.job_metadata import JobMetadata
|
||||
from flamenco.manager.model.job_settings import JobSettings
|
||||
from flamenco.manager.model.job_status import JobStatus
|
||||
from flamenco.manager.model.job_status_change import JobStatusChange
|
||||
from flamenco.manager.model.job_tasks_summary import JobTasksSummary
|
||||
from flamenco.manager.model.job_update import JobUpdate
|
||||
from flamenco.manager.model.jobs_query import JobsQuery
|
||||
from flamenco.manager.model.jobs_query_result import JobsQueryResult
|
||||
@ -40,6 +41,7 @@ from flamenco.manager.model.shaman_requirements_response import ShamanRequiremen
|
||||
from flamenco.manager.model.shaman_single_file_status import ShamanSingleFileStatus
|
||||
from flamenco.manager.model.submitted_job import SubmittedJob
|
||||
from flamenco.manager.model.task_status import TaskStatus
|
||||
from flamenco.manager.model.task_summary import TaskSummary
|
||||
from flamenco.manager.model.task_update import TaskUpdate
|
||||
from flamenco.manager.model.worker_registration import WorkerRegistration
|
||||
from flamenco.manager.model.worker_sign_on import WorkerSignOn
|
||||
|
@ -4,7 +4,7 @@ Render Farm manager API
|
||||
The `flamenco.manager` package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
|
||||
|
||||
- API version: 1.0.0
|
||||
- Package version: b699647e-dirty
|
||||
- Package version: e399b14e-dirty
|
||||
- Build package: org.openapitools.codegen.languages.PythonClientCodegen
|
||||
For more information, please visit [https://flamenco.io/](https://flamenco.io/)
|
||||
|
||||
@ -37,6 +37,7 @@ from flamenco.manager.model.available_job_types import AvailableJobTypes
|
||||
from flamenco.manager.model.error import Error
|
||||
from flamenco.manager.model.job import Job
|
||||
from flamenco.manager.model.job_status_change import JobStatusChange
|
||||
from flamenco.manager.model.job_tasks_summary import JobTasksSummary
|
||||
from flamenco.manager.model.jobs_query import JobsQuery
|
||||
from flamenco.manager.model.jobs_query_result import JobsQueryResult
|
||||
from flamenco.manager.model.submitted_job import SubmittedJob
|
||||
@ -69,6 +70,7 @@ All URIs are relative to *http://localhost*
|
||||
Class | Method | HTTP request | Description
|
||||
------------ | ------------- | ------------- | -------------
|
||||
*JobsApi* | [**fetch_job**](flamenco/manager/docs/JobsApi.md#fetch_job) | **GET** /api/jobs/{job_id} | Fetch info about the job.
|
||||
*JobsApi* | [**fetch_job_tasks**](flamenco/manager/docs/JobsApi.md#fetch_job_tasks) | **GET** /api/jobs/{job_id}/tasks | Fetch a summary of all tasks of the given job.
|
||||
*JobsApi* | [**get_job_type**](flamenco/manager/docs/JobsApi.md#get_job_type) | **GET** /api/jobs/type/{typeName} | Get single job type and its parameters.
|
||||
*JobsApi* | [**get_job_types**](flamenco/manager/docs/JobsApi.md#get_job_types) | **GET** /api/jobs/types | Get list of job types and their parameters.
|
||||
*JobsApi* | [**query_jobs**](flamenco/manager/docs/JobsApi.md#query_jobs) | **POST** /api/jobs/query | Fetch list of jobs.
|
||||
@ -106,6 +108,7 @@ Class | Method | HTTP request | Description
|
||||
- [JobSettings](flamenco/manager/docs/JobSettings.md)
|
||||
- [JobStatus](flamenco/manager/docs/JobStatus.md)
|
||||
- [JobStatusChange](flamenco/manager/docs/JobStatusChange.md)
|
||||
- [JobTasksSummary](flamenco/manager/docs/JobTasksSummary.md)
|
||||
- [JobUpdate](flamenco/manager/docs/JobUpdate.md)
|
||||
- [JobsQuery](flamenco/manager/docs/JobsQuery.md)
|
||||
- [JobsQueryResult](flamenco/manager/docs/JobsQueryResult.md)
|
||||
@ -122,6 +125,7 @@ Class | Method | HTTP request | Description
|
||||
- [ShamanSingleFileStatus](flamenco/manager/docs/ShamanSingleFileStatus.md)
|
||||
- [SubmittedJob](flamenco/manager/docs/SubmittedJob.md)
|
||||
- [TaskStatus](flamenco/manager/docs/TaskStatus.md)
|
||||
- [TaskSummary](flamenco/manager/docs/TaskSummary.md)
|
||||
- [TaskUpdate](flamenco/manager/docs/TaskUpdate.md)
|
||||
- [WorkerRegistration](flamenco/manager/docs/WorkerRegistration.md)
|
||||
- [WorkerSignOn](flamenco/manager/docs/WorkerSignOn.md)
|
||||
|
@ -56,6 +56,7 @@ type PersistenceService interface {
|
||||
|
||||
// Database queries.
|
||||
QueryJobs(ctx context.Context, query api.JobsQuery) ([]*persistence.Job, error)
|
||||
QueryJobTaskSummaries(ctx context.Context, jobUUID string) ([]*persistence.Task, error)
|
||||
}
|
||||
|
||||
var _ PersistenceService = (*persistence.DB)(nil)
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"git.blender.org/flamenco/internal/manager/persistence"
|
||||
"git.blender.org/flamenco/pkg/api"
|
||||
"github.com/google/uuid"
|
||||
"github.com/labstack/echo/v4"
|
||||
@ -58,3 +59,41 @@ func (f *Flamenco) QueryJobs(e echo.Context) error {
|
||||
}
|
||||
return e.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
func (f *Flamenco) FetchJobTasks(e echo.Context, jobID string) error {
|
||||
logger := requestLogger(e).With().
|
||||
Str("job", jobID).
|
||||
Logger()
|
||||
ctx := e.Request().Context()
|
||||
|
||||
if _, err := uuid.Parse(jobID); err != nil {
|
||||
logger.Debug().Msg("invalid job ID received")
|
||||
return sendAPIError(e, http.StatusBadRequest, "job ID not valid")
|
||||
}
|
||||
|
||||
tasks, err := f.persist.QueryJobTaskSummaries(ctx, jobID)
|
||||
if err != nil {
|
||||
logger.Warn().Err(err).Msg("error querying for jobs")
|
||||
return sendAPIError(e, http.StatusInternalServerError, "error querying for jobs")
|
||||
}
|
||||
|
||||
summaries := make([]api.TaskSummary, len(tasks))
|
||||
for i, task := range tasks {
|
||||
summaries[i] = taskDBtoSummary(task)
|
||||
}
|
||||
result := api.JobTasksSummary{
|
||||
Tasks: &summaries,
|
||||
}
|
||||
return e.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
func taskDBtoSummary(task *persistence.Task) api.TaskSummary {
|
||||
return api.TaskSummary{
|
||||
Id: task.UUID,
|
||||
Name: task.Name,
|
||||
Priority: task.Priority,
|
||||
Status: task.Status,
|
||||
TaskType: task.Type,
|
||||
Updated: task.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
@ -114,6 +114,21 @@ func (mr *MockPersistenceServiceMockRecorder) FetchWorker(arg0, arg1 interface{}
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchWorker", reflect.TypeOf((*MockPersistenceService)(nil).FetchWorker), arg0, arg1)
|
||||
}
|
||||
|
||||
// QueryJobTaskSummaries mocks base method.
|
||||
func (m *MockPersistenceService) QueryJobTaskSummaries(arg0 context.Context, arg1 string) ([]*persistence.Task, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "QueryJobTaskSummaries", arg0, arg1)
|
||||
ret0, _ := ret[0].([]*persistence.Task)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// QueryJobTaskSummaries indicates an expected call of QueryJobTaskSummaries.
|
||||
func (mr *MockPersistenceServiceMockRecorder) QueryJobTaskSummaries(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryJobTaskSummaries", reflect.TypeOf((*MockPersistenceService)(nil).QueryJobTaskSummaries), arg0, arg1)
|
||||
}
|
||||
|
||||
// QueryJobs mocks base method.
|
||||
func (m *MockPersistenceService) QueryJobs(arg0 context.Context, arg1 api.JobsQuery) ([]*persistence.Job, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -68,3 +68,19 @@ func (db *DB) QueryJobs(ctx context.Context, apiQ api.JobsQuery) ([]*Job, error)
|
||||
tx := q.Scan(&result)
|
||||
return result, tx.Error
|
||||
}
|
||||
|
||||
// QueryJobTaskSummaries retrieves all tasks of the job, but not all fields of those tasks.
|
||||
// Fields are synchronised with api.TaskSummary.
|
||||
func (db *DB) QueryJobTaskSummaries(ctx context.Context, jobUUID string) ([]*Task, error) {
|
||||
logger := log.Ctx(ctx)
|
||||
logger.Debug().Str("job", jobUUID).Msg("queryingtask summaries")
|
||||
|
||||
var result []*Task
|
||||
tx := db.gormDB.WithContext(ctx).Model(&Task{}).
|
||||
Select("tasks.id", "tasks.uuid", "tasks.name", "tasks.priority", "tasks.status", "tasks.type", "tasks.updated_at").
|
||||
Joins("left join jobs on jobs.uuid = ?", jobUUID).
|
||||
// Where("jobs.uuid=?", jobUUID).
|
||||
Scan(&result)
|
||||
|
||||
return result, tx.Error
|
||||
}
|
||||
|
@ -104,3 +104,29 @@ func TestQueryMetadata(t *testing.T) {
|
||||
assert.Equal(t, otherJob.ID, result[0].ID, "status is %s", result[0].Status)
|
||||
assert.Equal(t, testJob.ID, result[1].ID, "status is %s", result[1].Status)
|
||||
}
|
||||
|
||||
func TestFetchJobSummary(t *testing.T) {
|
||||
ctx, close, db, job, authoredJob := jobTasksTestFixtures(t)
|
||||
defer close()
|
||||
|
||||
expectTaskUUIDs := map[string]bool{}
|
||||
for _, task := range authoredJob.Tasks {
|
||||
expectTaskUUIDs[task.UUID] = true
|
||||
}
|
||||
|
||||
// Create another test job, just to check we get the right tasks back.
|
||||
otherAuthoredJob := createTestAuthoredJobWithTasks()
|
||||
otherAuthoredJob.Status = api.JobStatusActive
|
||||
otherAuthoredJob.Tasks = []job_compilers.AuthoredTask{}
|
||||
otherAuthoredJob.JobID = "138678c8-efd0-452b-ac05-397ff4c02b26"
|
||||
otherAuthoredJob.Metadata["project"] = "Other Project"
|
||||
persistAuthoredJob(t, ctx, db, otherAuthoredJob)
|
||||
|
||||
summaries, err := db.QueryJobTaskSummaries(ctx, job.UUID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Len(t, summaries, len(expectTaskUUIDs))
|
||||
for _, summary := range summaries {
|
||||
assert.True(t, expectTaskUUIDs[summary.UUID], "%q should be in %v", summary.UUID, expectTaskUUIDs)
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,26 @@ func (m *MockFlamencoClient) EXPECT() *MockFlamencoClientMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// FetchJobTasksWithResponse mocks base method.
|
||||
func (m *MockFlamencoClient) FetchJobTasksWithResponse(arg0 context.Context, arg1 string, arg2 ...api.RequestEditorFn) (*api.FetchJobTasksResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "FetchJobTasksWithResponse", varargs...)
|
||||
ret0, _ := ret[0].(*api.FetchJobTasksResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// FetchJobTasksWithResponse indicates an expected call of FetchJobTasksWithResponse.
|
||||
func (mr *MockFlamencoClientMockRecorder) FetchJobTasksWithResponse(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchJobTasksWithResponse", reflect.TypeOf((*MockFlamencoClient)(nil).FetchJobTasksWithResponse), varargs...)
|
||||
}
|
||||
|
||||
// FetchJobWithResponse mocks base method.
|
||||
func (m *MockFlamencoClient) FetchJobWithResponse(arg0 context.Context, arg1 string, arg2 ...api.RequestEditorFn) (*api.FetchJobResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -351,6 +351,29 @@ paths:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
|
||||
/api/jobs/{job_id}/tasks:
|
||||
summary: Access tasks of this job.
|
||||
get:
|
||||
operationId: fetchJobTasks
|
||||
summary: Fetch a summary of all tasks of the given job.
|
||||
tags: [jobs]
|
||||
parameters:
|
||||
- name: job_id
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, format: uuid }
|
||||
responses:
|
||||
"200":
|
||||
description: Get summaries of the tasks of this job.
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/JobTasksSummary" }
|
||||
default:
|
||||
description: Unexpected error.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
|
||||
## Shaman
|
||||
|
||||
@ -783,7 +806,7 @@ components:
|
||||
updated:
|
||||
type: string
|
||||
format: date-time
|
||||
description: Creation timestamp
|
||||
description: Timestamp of last update.
|
||||
status: { $ref: "#/components/schemas/JobStatus" }
|
||||
activity: { type: string, description: "Description of the last activity on this job." }
|
||||
required: [id, created, updated, status, activity]
|
||||
@ -841,6 +864,27 @@ components:
|
||||
items: { $ref: "#/components/schemas/Job" }
|
||||
required: [jobs]
|
||||
|
||||
JobTasksSummary:
|
||||
description: "Simplified list of tasks of a job. Contains all tasks, but not all info of each task."
|
||||
type: object
|
||||
properties:
|
||||
tasks:
|
||||
type: array
|
||||
items: { $ref: "#/components/schemas/TaskSummary" }
|
||||
required: [jobs]
|
||||
|
||||
TaskSummary:
|
||||
type: object
|
||||
description: Just enough information about the task to show in the job's task list.
|
||||
properties:
|
||||
id: { type: string, format: uuid }
|
||||
name: { type: string }
|
||||
status: { $ref: "#/components/schemas/TaskStatus" }
|
||||
priority: { type: integer }
|
||||
task_type: { type: string }
|
||||
updated: { type: string, format: date-time }
|
||||
required: [id, name, status, priority, task_type, updated]
|
||||
|
||||
JobStatusChange:
|
||||
type: object
|
||||
properties:
|
||||
|
@ -117,6 +117,9 @@ type ClientInterface interface {
|
||||
|
||||
SetJobStatus(ctx context.Context, jobId string, body SetJobStatusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
|
||||
|
||||
// FetchJobTasks request
|
||||
FetchJobTasks(ctx context.Context, jobId string, reqEditors ...RequestEditorFn) (*http.Response, error)
|
||||
|
||||
// GetVersion request
|
||||
GetVersion(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
|
||||
|
||||
@ -286,6 +289,18 @@ func (c *Client) SetJobStatus(ctx context.Context, jobId string, body SetJobStat
|
||||
return c.Client.Do(req)
|
||||
}
|
||||
|
||||
func (c *Client) FetchJobTasks(ctx context.Context, jobId string, reqEditors ...RequestEditorFn) (*http.Response, error) {
|
||||
req, err := NewFetchJobTasksRequest(c.Server, jobId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req = req.WithContext(ctx)
|
||||
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.Client.Do(req)
|
||||
}
|
||||
|
||||
func (c *Client) GetVersion(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
|
||||
req, err := NewGetVersionRequest(c.Server)
|
||||
if err != nil {
|
||||
@ -751,6 +766,40 @@ func NewSetJobStatusRequestWithBody(server string, jobId string, contentType str
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// NewFetchJobTasksRequest generates requests for FetchJobTasks
|
||||
func NewFetchJobTasksRequest(server string, jobId string) (*http.Request, error) {
|
||||
var err error
|
||||
|
||||
var pathParam0 string
|
||||
|
||||
pathParam0, err = runtime.StyleParamWithLocation("simple", false, "job_id", runtime.ParamLocationPath, jobId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
serverURL, err := url.Parse(server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
operationPath := fmt.Sprintf("/api/jobs/%s/tasks", pathParam0)
|
||||
if operationPath[0] == '/' {
|
||||
operationPath = "." + operationPath
|
||||
}
|
||||
|
||||
queryURL, err := serverURL.Parse(operationPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", queryURL.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// NewGetVersionRequest generates requests for GetVersion
|
||||
func NewGetVersionRequest(server string) (*http.Request, error) {
|
||||
var err error
|
||||
@ -1282,6 +1331,9 @@ type ClientWithResponsesInterface interface {
|
||||
|
||||
SetJobStatusWithResponse(ctx context.Context, jobId string, body SetJobStatusJSONRequestBody, reqEditors ...RequestEditorFn) (*SetJobStatusResponse, error)
|
||||
|
||||
// FetchJobTasks request
|
||||
FetchJobTasksWithResponse(ctx context.Context, jobId string, reqEditors ...RequestEditorFn) (*FetchJobTasksResponse, error)
|
||||
|
||||
// GetVersion request
|
||||
GetVersionWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetVersionResponse, error)
|
||||
|
||||
@ -1487,6 +1539,29 @@ func (r SetJobStatusResponse) StatusCode() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
type FetchJobTasksResponse struct {
|
||||
Body []byte
|
||||
HTTPResponse *http.Response
|
||||
JSON200 *JobTasksSummary
|
||||
JSONDefault *Error
|
||||
}
|
||||
|
||||
// Status returns HTTPResponse.Status
|
||||
func (r FetchJobTasksResponse) Status() string {
|
||||
if r.HTTPResponse != nil {
|
||||
return r.HTTPResponse.Status
|
||||
}
|
||||
return http.StatusText(0)
|
||||
}
|
||||
|
||||
// StatusCode returns HTTPResponse.StatusCode
|
||||
func (r FetchJobTasksResponse) StatusCode() int {
|
||||
if r.HTTPResponse != nil {
|
||||
return r.HTTPResponse.StatusCode
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type GetVersionResponse struct {
|
||||
Body []byte
|
||||
HTTPResponse *http.Response
|
||||
@ -1848,6 +1923,15 @@ func (c *ClientWithResponses) SetJobStatusWithResponse(ctx context.Context, jobI
|
||||
return ParseSetJobStatusResponse(rsp)
|
||||
}
|
||||
|
||||
// FetchJobTasksWithResponse request returning *FetchJobTasksResponse
|
||||
func (c *ClientWithResponses) FetchJobTasksWithResponse(ctx context.Context, jobId string, reqEditors ...RequestEditorFn) (*FetchJobTasksResponse, error) {
|
||||
rsp, err := c.FetchJobTasks(ctx, jobId, reqEditors...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ParseFetchJobTasksResponse(rsp)
|
||||
}
|
||||
|
||||
// GetVersionWithResponse request returning *GetVersionResponse
|
||||
func (c *ClientWithResponses) GetVersionWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetVersionResponse, error) {
|
||||
rsp, err := c.GetVersion(ctx, reqEditors...)
|
||||
@ -2200,6 +2284,39 @@ func ParseSetJobStatusResponse(rsp *http.Response) (*SetJobStatusResponse, error
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// ParseFetchJobTasksResponse parses an HTTP response from a FetchJobTasksWithResponse call
|
||||
func ParseFetchJobTasksResponse(rsp *http.Response) (*FetchJobTasksResponse, error) {
|
||||
bodyBytes, err := ioutil.ReadAll(rsp.Body)
|
||||
defer func() { _ = rsp.Body.Close() }()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := &FetchJobTasksResponse{
|
||||
Body: bodyBytes,
|
||||
HTTPResponse: rsp,
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
|
||||
var dest JobTasksSummary
|
||||
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response.JSON200 = &dest
|
||||
|
||||
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && true:
|
||||
var dest Error
|
||||
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response.JSONDefault = &dest
|
||||
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// ParseGetVersionResponse parses an HTTP response from a GetVersionWithResponse call
|
||||
func ParseGetVersionResponse(rsp *http.Response) (*GetVersionResponse, error) {
|
||||
bodyBytes, err := ioutil.ReadAll(rsp.Body)
|
||||
|
@ -34,6 +34,9 @@ type ServerInterface interface {
|
||||
|
||||
// (POST /api/jobs/{job_id}/setstatus)
|
||||
SetJobStatus(ctx echo.Context, jobId string) error
|
||||
// Fetch a summary of all tasks of the given job.
|
||||
// (GET /api/jobs/{job_id}/tasks)
|
||||
FetchJobTasks(ctx echo.Context, jobId string) error
|
||||
// Get the Flamenco version of this Manager
|
||||
// (GET /api/version)
|
||||
GetVersion(ctx echo.Context) error
|
||||
@ -162,6 +165,22 @@ func (w *ServerInterfaceWrapper) SetJobStatus(ctx echo.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// FetchJobTasks converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) FetchJobTasks(ctx echo.Context) error {
|
||||
var err error
|
||||
// ------------- Path parameter "job_id" -------------
|
||||
var jobId string
|
||||
|
||||
err = runtime.BindStyledParameterWithLocation("simple", false, "job_id", runtime.ParamLocationPath, ctx.Param("job_id"), &jobId)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter job_id: %s", err))
|
||||
}
|
||||
|
||||
// Invoke the callback with all the unmarshalled arguments
|
||||
err = w.Handler.FetchJobTasks(ctx, jobId)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetVersion converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) GetVersion(ctx echo.Context) error {
|
||||
var err error
|
||||
@ -389,6 +408,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
|
||||
router.GET(baseURL+"/api/jobs/types", wrapper.GetJobTypes)
|
||||
router.GET(baseURL+"/api/jobs/:job_id", wrapper.FetchJob)
|
||||
router.POST(baseURL+"/api/jobs/:job_id/setstatus", wrapper.SetJobStatus)
|
||||
router.GET(baseURL+"/api/jobs/:job_id/tasks", wrapper.FetchJobTasks)
|
||||
router.GET(baseURL+"/api/version", wrapper.GetVersion)
|
||||
router.POST(baseURL+"/api/worker/register-worker", wrapper.RegisterWorker)
|
||||
router.POST(baseURL+"/api/worker/sign-off", wrapper.SignOff)
|
||||
|
@ -18,109 +18,112 @@ import (
|
||||
// Base64 encoded, gzipped, json marshaled Swagger object
|
||||
var swaggerSpec = []string{
|
||||
|
||||
"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",
|
||||
"vqPX9dn1/wQAAP//GzfZKqRpAAA=",
|
||||
"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",
|
||||
"1Gk663t6Xb69/J8AAAD//wGTUz2RbgAA",
|
||||
}
|
||||
|
||||
// GetSwagger returns the content of the embedded swagger specification file
|
||||
|
@ -213,7 +213,7 @@ type Job struct {
|
||||
Id string `json:"id"`
|
||||
Status JobStatus `json:"status"`
|
||||
|
||||
// Creation timestamp
|
||||
// Timestamp of last update.
|
||||
Updated time.Time `json:"updated"`
|
||||
}
|
||||
|
||||
@ -237,6 +237,11 @@ type JobStatusChange struct {
|
||||
Status JobStatus `json:"status"`
|
||||
}
|
||||
|
||||
// Simplified list of tasks of a job. Contains all tasks, but not all info of each task.
|
||||
type JobTasksSummary struct {
|
||||
Tasks *[]TaskSummary `json:"tasks,omitempty"`
|
||||
}
|
||||
|
||||
// Subset of a Job, sent over SocketIO when a job changes. For new jobs, `previous_status` will be excluded.
|
||||
type JobUpdate struct {
|
||||
// UUID of the Job
|
||||
@ -379,6 +384,16 @@ type SubmittedJob struct {
|
||||
// TaskStatus defines model for TaskStatus.
|
||||
type TaskStatus string
|
||||
|
||||
// Just enough information about the task to show in the job's task list.
|
||||
type TaskSummary struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Priority int `json:"priority"`
|
||||
Status TaskStatus `json:"status"`
|
||||
TaskType string `json:"task_type"`
|
||||
Updated time.Time `json:"updated"`
|
||||
}
|
||||
|
||||
// TaskUpdate is sent by a Worker to update the status & logs of a task it's executing.
|
||||
type TaskUpdate struct {
|
||||
// One-liner to indicate what's currently happening with the task. Overwrites previously sent activity strings.
|
||||
|
@ -55,7 +55,7 @@ class ApiClient {
|
||||
* @default {}
|
||||
*/
|
||||
this.defaultHeaders = {
|
||||
'User-Agent': 'Flamenco/b699647e-dirty / webbrowser'
|
||||
'User-Agent': 'Flamenco/e399b14e-dirty / webbrowser'
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -26,6 +26,7 @@ import Job from './model/Job';
|
||||
import JobAllOf from './model/JobAllOf';
|
||||
import JobStatus from './model/JobStatus';
|
||||
import JobStatusChange from './model/JobStatusChange';
|
||||
import JobTasksSummary from './model/JobTasksSummary';
|
||||
import JobUpdate from './model/JobUpdate';
|
||||
import JobsQuery from './model/JobsQuery';
|
||||
import JobsQueryResult from './model/JobsQueryResult';
|
||||
@ -42,6 +43,7 @@ import ShamanRequirementsResponse from './model/ShamanRequirementsResponse';
|
||||
import ShamanSingleFileStatus from './model/ShamanSingleFileStatus';
|
||||
import SubmittedJob from './model/SubmittedJob';
|
||||
import TaskStatus from './model/TaskStatus';
|
||||
import TaskSummary from './model/TaskSummary';
|
||||
import TaskUpdate from './model/TaskUpdate';
|
||||
import WorkerRegistration from './model/WorkerRegistration';
|
||||
import WorkerSignOn from './model/WorkerSignOn';
|
||||
@ -170,6 +172,12 @@ export {
|
||||
*/
|
||||
JobStatusChange,
|
||||
|
||||
/**
|
||||
* The JobTasksSummary model constructor.
|
||||
* @property {module:model/JobTasksSummary}
|
||||
*/
|
||||
JobTasksSummary,
|
||||
|
||||
/**
|
||||
* The JobUpdate model constructor.
|
||||
* @property {module:model/JobUpdate}
|
||||
@ -266,6 +274,12 @@ export {
|
||||
*/
|
||||
TaskStatus,
|
||||
|
||||
/**
|
||||
* The TaskSummary model constructor.
|
||||
* @property {module:model/TaskSummary}
|
||||
*/
|
||||
TaskSummary,
|
||||
|
||||
/**
|
||||
* The TaskUpdate model constructor.
|
||||
* @property {module:model/TaskUpdate}
|
||||
|
@ -18,6 +18,7 @@ import AvailableJobTypes from '../model/AvailableJobTypes';
|
||||
import Error from '../model/Error';
|
||||
import Job from '../model/Job';
|
||||
import JobStatusChange from '../model/JobStatusChange';
|
||||
import JobTasksSummary from '../model/JobTasksSummary';
|
||||
import JobsQuery from '../model/JobsQuery';
|
||||
import JobsQueryResult from '../model/JobsQueryResult';
|
||||
import SubmittedJob from '../model/SubmittedJob';
|
||||
@ -88,6 +89,52 @@ export default class JobsApi {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetch a summary of all tasks of the given job.
|
||||
* @param {String} jobId
|
||||
* @return {Promise} a {@link https://www.promisejs.org/|Promise}, with an object containing data of type {@link module:model/JobTasksSummary} and HTTP response
|
||||
*/
|
||||
fetchJobTasksWithHttpInfo(jobId) {
|
||||
let postBody = null;
|
||||
// verify the required parameter 'jobId' is set
|
||||
if (jobId === undefined || jobId === null) {
|
||||
throw new Error("Missing the required parameter 'jobId' when calling fetchJobTasks");
|
||||
}
|
||||
|
||||
let pathParams = {
|
||||
'job_id': jobId
|
||||
};
|
||||
let queryParams = {
|
||||
};
|
||||
let headerParams = {
|
||||
};
|
||||
let formParams = {
|
||||
};
|
||||
|
||||
let authNames = [];
|
||||
let contentTypes = [];
|
||||
let accepts = ['application/json'];
|
||||
let returnType = JobTasksSummary;
|
||||
return this.apiClient.callApi(
|
||||
'/api/jobs/{job_id}/tasks', 'GET',
|
||||
pathParams, queryParams, headerParams, formParams, postBody,
|
||||
authNames, contentTypes, accepts, returnType, null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a summary of all tasks of the given job.
|
||||
* @param {String} jobId
|
||||
* @return {Promise} a {@link https://www.promisejs.org/|Promise}, with data of type {@link module:model/JobTasksSummary}
|
||||
*/
|
||||
fetchJobTasks(jobId) {
|
||||
return this.fetchJobTasksWithHttpInfo(jobId)
|
||||
.then(function(response_and_data) {
|
||||
return response_and_data.data;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get single job type and its parameters.
|
||||
* @param {String} typeName
|
||||
|
@ -32,7 +32,7 @@ class Job {
|
||||
* @param priority {Number}
|
||||
* @param id {String} UUID of the Job
|
||||
* @param created {Date} Creation timestamp
|
||||
* @param updated {Date} Creation timestamp
|
||||
* @param updated {Date} Timestamp of last update.
|
||||
* @param status {module:model/JobStatus}
|
||||
* @param activity {String} Description of the last activity on this job.
|
||||
*/
|
||||
@ -147,7 +147,7 @@ Job.prototype['id'] = undefined;
|
||||
Job.prototype['created'] = undefined;
|
||||
|
||||
/**
|
||||
* Creation timestamp
|
||||
* Timestamp of last update.
|
||||
* @member {Date} updated
|
||||
*/
|
||||
Job.prototype['updated'] = undefined;
|
||||
@ -199,7 +199,7 @@ JobAllOf.prototype['id'] = undefined;
|
||||
*/
|
||||
JobAllOf.prototype['created'] = undefined;
|
||||
/**
|
||||
* Creation timestamp
|
||||
* Timestamp of last update.
|
||||
* @member {Date} updated
|
||||
*/
|
||||
JobAllOf.prototype['updated'] = undefined;
|
||||
|
@ -25,7 +25,7 @@ class JobAllOf {
|
||||
* @alias module:model/JobAllOf
|
||||
* @param id {String} UUID of the Job
|
||||
* @param created {Date} Creation timestamp
|
||||
* @param updated {Date} Creation timestamp
|
||||
* @param updated {Date} Timestamp of last update.
|
||||
* @param status {module:model/JobStatus}
|
||||
* @param activity {String} Description of the last activity on this job.
|
||||
*/
|
||||
@ -93,7 +93,7 @@ JobAllOf.prototype['id'] = undefined;
|
||||
JobAllOf.prototype['created'] = undefined;
|
||||
|
||||
/**
|
||||
* Creation timestamp
|
||||
* Timestamp of last update.
|
||||
* @member {Date} updated
|
||||
*/
|
||||
JobAllOf.prototype['updated'] = undefined;
|
||||
|
73
web/app/src/manager-api/model/JobTasksSummary.js
Normal file
73
web/app/src/manager-api/model/JobTasksSummary.js
Normal file
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Flamenco manager
|
||||
* Render Farm manager API
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*
|
||||
*/
|
||||
|
||||
import ApiClient from '../ApiClient';
|
||||
import TaskSummary from './TaskSummary';
|
||||
|
||||
/**
|
||||
* The JobTasksSummary model module.
|
||||
* @module model/JobTasksSummary
|
||||
* @version 0.0.0
|
||||
*/
|
||||
class JobTasksSummary {
|
||||
/**
|
||||
* Constructs a new <code>JobTasksSummary</code>.
|
||||
* Simplified list of tasks of a job. Contains all tasks, but not all info of each task.
|
||||
* @alias module:model/JobTasksSummary
|
||||
*/
|
||||
constructor() {
|
||||
|
||||
JobTasksSummary.initialize(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the fields of this object.
|
||||
* This method is used by the constructors of any subclasses, in order to implement multiple inheritance (mix-ins).
|
||||
* Only for internal use.
|
||||
*/
|
||||
static initialize(obj) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>JobTasksSummary</code> from a plain JavaScript object, optionally creating a new instance.
|
||||
* Copies all relevant properties from <code>data</code> to <code>obj</code> if supplied or a new instance if not.
|
||||
* @param {Object} data The plain JavaScript object bearing properties of interest.
|
||||
* @param {module:model/JobTasksSummary} obj Optional instance to populate.
|
||||
* @return {module:model/JobTasksSummary} The populated <code>JobTasksSummary</code> instance.
|
||||
*/
|
||||
static constructFromObject(data, obj) {
|
||||
if (data) {
|
||||
obj = obj || new JobTasksSummary();
|
||||
|
||||
if (data.hasOwnProperty('tasks')) {
|
||||
obj['tasks'] = ApiClient.convertToType(data['tasks'], [TaskSummary]);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @member {Array.<module:model/TaskSummary>} tasks
|
||||
*/
|
||||
JobTasksSummary.prototype['tasks'] = undefined;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export default JobTasksSummary;
|
||||
|
125
web/app/src/manager-api/model/TaskSummary.js
Normal file
125
web/app/src/manager-api/model/TaskSummary.js
Normal file
@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Flamenco manager
|
||||
* Render Farm manager API
|
||||
*
|
||||
* The version of the OpenAPI document: 1.0.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*
|
||||
*/
|
||||
|
||||
import ApiClient from '../ApiClient';
|
||||
import TaskStatus from './TaskStatus';
|
||||
|
||||
/**
|
||||
* The TaskSummary model module.
|
||||
* @module model/TaskSummary
|
||||
* @version 0.0.0
|
||||
*/
|
||||
class TaskSummary {
|
||||
/**
|
||||
* Constructs a new <code>TaskSummary</code>.
|
||||
* Just enough information about the task to show in the job's task list.
|
||||
* @alias module:model/TaskSummary
|
||||
* @param id {String}
|
||||
* @param name {String}
|
||||
* @param status {module:model/TaskStatus}
|
||||
* @param priority {Number}
|
||||
* @param taskType {String}
|
||||
* @param updated {Date}
|
||||
*/
|
||||
constructor(id, name, status, priority, taskType, updated) {
|
||||
|
||||
TaskSummary.initialize(this, id, name, status, priority, taskType, updated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the fields of this object.
|
||||
* This method is used by the constructors of any subclasses, in order to implement multiple inheritance (mix-ins).
|
||||
* Only for internal use.
|
||||
*/
|
||||
static initialize(obj, id, name, status, priority, taskType, updated) {
|
||||
obj['id'] = id;
|
||||
obj['name'] = name;
|
||||
obj['status'] = status;
|
||||
obj['priority'] = priority;
|
||||
obj['task_type'] = taskType;
|
||||
obj['updated'] = updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>TaskSummary</code> from a plain JavaScript object, optionally creating a new instance.
|
||||
* Copies all relevant properties from <code>data</code> to <code>obj</code> if supplied or a new instance if not.
|
||||
* @param {Object} data The plain JavaScript object bearing properties of interest.
|
||||
* @param {module:model/TaskSummary} obj Optional instance to populate.
|
||||
* @return {module:model/TaskSummary} The populated <code>TaskSummary</code> instance.
|
||||
*/
|
||||
static constructFromObject(data, obj) {
|
||||
if (data) {
|
||||
obj = obj || new TaskSummary();
|
||||
|
||||
if (data.hasOwnProperty('id')) {
|
||||
obj['id'] = ApiClient.convertToType(data['id'], 'String');
|
||||
}
|
||||
if (data.hasOwnProperty('name')) {
|
||||
obj['name'] = ApiClient.convertToType(data['name'], 'String');
|
||||
}
|
||||
if (data.hasOwnProperty('status')) {
|
||||
obj['status'] = TaskStatus.constructFromObject(data['status']);
|
||||
}
|
||||
if (data.hasOwnProperty('priority')) {
|
||||
obj['priority'] = ApiClient.convertToType(data['priority'], 'Number');
|
||||
}
|
||||
if (data.hasOwnProperty('task_type')) {
|
||||
obj['task_type'] = ApiClient.convertToType(data['task_type'], 'String');
|
||||
}
|
||||
if (data.hasOwnProperty('updated')) {
|
||||
obj['updated'] = ApiClient.convertToType(data['updated'], 'Date');
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @member {String} id
|
||||
*/
|
||||
TaskSummary.prototype['id'] = undefined;
|
||||
|
||||
/**
|
||||
* @member {String} name
|
||||
*/
|
||||
TaskSummary.prototype['name'] = undefined;
|
||||
|
||||
/**
|
||||
* @member {module:model/TaskStatus} status
|
||||
*/
|
||||
TaskSummary.prototype['status'] = undefined;
|
||||
|
||||
/**
|
||||
* @member {Number} priority
|
||||
*/
|
||||
TaskSummary.prototype['priority'] = undefined;
|
||||
|
||||
/**
|
||||
* @member {String} task_type
|
||||
*/
|
||||
TaskSummary.prototype['task_type'] = undefined;
|
||||
|
||||
/**
|
||||
* @member {Date} updated
|
||||
*/
|
||||
TaskSummary.prototype['updated'] = undefined;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export default TaskSummary;
|
||||
|
Loading…
x
Reference in New Issue
Block a user