diff --git a/.travis.yml b/.travis.yml index 87e78b7335b..273f60d8612 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,6 +45,8 @@ matrix: - pushd services/director; pip3 install -r requirements/ci.txt; popd - pip3 install packages/director-sdk/python - pushd services/web/server; pip3 install -r requirements/ci.txt; popd + - pip3 install -r apis/tests/requirements.txt + - pip3 install -r services/apihub/tests/requirements.txt before_script: - pylint --version diff --git a/Makefile b/Makefile index 1e6c2c363b7..20bde72a3f9 100644 --- a/Makefile +++ b/Makefile @@ -87,6 +87,8 @@ before_test: ${DOCKER_COMPOSE} -f packages/simcore-sdk/tests/docker-compose.yml build run_test: + pytest -v apis/tests + pytest -v services/apihub/tests pytest --cov=pytest_docker -v packages/pytest_docker/tests pytest --cov=s3wrapper -v packages/s3wrapper/tests pytest --cov=simcore_sdk -v packages/simcore-sdk/tests diff --git a/apis/README.md b/apis/README.md new file mode 100644 index 00000000000..2cfa77cac5d --- /dev/null +++ b/apis/README.md @@ -0,0 +1,87 @@ +# APIs development guidelines + +# Concept + +REST APIs and models (defined as openAPI- or JSON-schemas) are defined in a central location (/apis) to allow for "design-first" development. + +# Development guidelines + +## Standards + +The oSparc platform uses the following standards: +- REST API: [Open API v3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md) +- Models and configuration [JSON Schema](https://json-schema.org/) + +## Folder structure + +```bash +/apis/ # base folder +/apis/director/ # service name folder (e.g. for director service) +/apis/director/v0/ # service version (v0 for development, then v1, v2... only major) +/apis/director/v0/openapi.yaml # openapi specifications in YAML +/apis/director/v0/schemas/ # schemas only used by the director API +/apis/director/v0/schemas/services.yaml # openapi encoded service only schema + +/apis/shared/ # shared apis/schemas base folder +/apis/shared/schemas/ # sub folder for schemas +/apis/shared/schemas/health_check.yaml # openapi encoded shared schema +/apis/shared/schemas/node-meta.json # jsonschema encoded shared schema +/apis/shared/schemas/v1/error.yaml # openapi encoded shaared schema for version 1 +/apis/shared/schemas/v2/error.yaml # openapi encoded shaared schema for version 2 + +/tests/ # python tests folder to check schemas validity +/tests/requirements.txt # requirements for python tests +``` + +## Organization + +### Openapi specifications file + +Each API is defined within a file __openapi.yaml__ in YAML format. The file shall be located in the a subfolder named after the service/package and the major version subfolder. + +#### Version subfolder + +For initial development, the version shall be 0.1.0 and the subfolder v0 +For release, the version shall start from 1.0.0 and subfolder v1. +The subolder digit corresponds to the version major digits. It shall be modified only when changes are not backwards compatible (e.g. changing a return value, removing parameters or resource, ...). + +#### Schemas in separate files + +Schemas shall always be defined in separate files. + +Schemas format shall be either OpenAPI v3 or JSON schema Draft#7. + +If these schemas are pertinent only to the current API they shall be contained together with the openapi specifications file inside a __schemas__ subfolder. +If these schemas are shared with other APIs they should be located in the __/shared/schemas__ subfolder. + +#### Versioning shared schemas + +NOTE: If shared schemas need backward incompatible changes, then a new major version of this specific shared schema is necessary and all APIs that rely on this specific schema will need to be upgraded. +In that case, a version subfolder shall be added in the __/shared/__ subfolder and the relevant schemas shall be moved there. + +### Schemas defined with JSONSchema format that are used together with OpenAPI + +Mixing JSONSchema with OpenAPI schema needs some additional steps: + +1. Define the JSONSchema schema. +2. Convert the JSONSchema formatted file to OpenAPI formatted file using the [converter](../scripts/jsonschema/openapi_converter). +3. In the openapi specifications file ref the converted OpenAPI schema file. + +## Using the openAPI + +### Python: Current status (using aiohttp-apiset) + +The current python-based packages use the aiohttp-apiset library to create routes from the defined API. The aiohttp-apiset library requires a physical file to create the routes. Therefore one needs to generate that file by following: + +1. Generate a 1 file OpenAPI formatted file using [prance](https://pypi.org/project/prance/). By using [openapi-resolver](../scripts/openapi/oas_resolver). +2. Copy the generated file in a folder in the python-based code and use it. + +### Python: in development and should be available soon + +Using the library [openapi-core](https://github.com/p1c2u/openapi-core) the library is able to download the api at starting point. +The [apihub service](../services/apihub) serves the apis and schemas to the internal parts of the oSparc platform. + +## references + +- [defining reusable components - good practices](https://dev.to/mikeralphson/defining-reusable-components-with-the-openapi-specification-4077) +- [official guidelines on OAS re-usability](https://github.com/OAI/OpenAPI-Specification/blob/master/guidelines/v2.0/REUSE.md) \ No newline at end of file diff --git a/apis/director/v0/openapi.yaml b/apis/director/v0/openapi.yaml new file mode 100644 index 00000000000..95a831c5430 --- /dev/null +++ b/apis/director/v0/openapi.yaml @@ -0,0 +1,313 @@ +openapi: "3.0.0" +info: + description: This is the oSparc's director API + version: 1.0.0 + title: Director API + # put the contact info for your development or API team + contact: + name: IT'IS Foundation + email: support@simcore.com + license: + name: MIT + url: https://github.com/ITISFoundation/osparc-simcore/blob/master/LICENSE + +servers: + - url: http://{host}:{port}/{version} + description: Development server + variables: + host: + default: 'localhost' + port: + default: '8001' + version: + default: 'v0' + enum: + - 'v0' + +# tags are used for organizing operations +tags: +- name: admins + description: Secured Admin-only calls +- name: developers + description: Operations available to regular developers +- name: users + description: Operations available to regular users + +paths: + /: + get: + tags: + - users + summary: Service health-check endpoint + description: Some general information on the API and state of the service behind + operationId: root_get + responses: + "200": + description: Service information + content: + application/json: + schema: + $ref: '../../shared/schemas/health_check.yaml#/HealthCheckEnveloped' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '../../shared/schemas/error.yaml#/ErrorEnveloped' + + /services: + get: + tags: + - users + summary: Lists available services in the oSparc platform + description: Lists available services in the oSparc platform + operationId: services_get + parameters: + - $ref: '#/components/parameters/ServiceType' + responses: + "200": + description: Success, returns the list of available services + content: + application/json: + schema: + $ref: '../../shared/schemas/services.yaml#/ServicesEnveloped' + "401": + description: Unauthorized access + content: + application/json: + schema: + $ref: '../../shared/schemas/error.yaml#/ErrorEnveloped' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '../../shared/schemas/error.yaml#/ErrorEnveloped' + + /services/{service_key}/{service_version}: + get: + tags: + - users + summary: Returns details of the selected service if available in the oSparc platform + description: Returns details of the selected service if available in the oSparc platform + operationId: services_by_key_version_get + parameters: + - $ref: '#/components/parameters/ServiceKeyPath' + - $ref: '#/components/parameters/ServiceVersionPath' + responses: + "200": + description: Success, returns the details of the service + content: + application/json: + schema: + $ref: '../../shared/schemas/services.yaml#/ServicesEnveloped' + "401": + description: Unauthorized access + content: + application/json: + schema: + $ref: '../../shared/schemas/error.yaml#/ErrorEnveloped' + "404": + description: Service not found + content: + application/json: + schema: + $ref: '../../shared/schemas/error.yaml#/ErrorEnveloped' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '../../shared/schemas/error.yaml#/ErrorEnveloped' + + /running_interactive_services: + post: + tags: + - users + summary: Starts an interactive service in the oSparc platform and returns its entrypoint + description: Starts an interactive service in the oSparc platform and returns its entrypoint + operationId: running_interactive_services_post + parameters: + - $ref: '#/components/parameters/ServiceKey' + - $ref: '#/components/parameters/ServiceVersion' + - $ref: '#/components/parameters/AssignmentUuid' + responses: + "201": + description: Succesfully created the service in the oSparc platform. Returns the location where the service runs. + content: + application/json: + schema: + $ref: '../../shared/schemas/running_service.yaml#/RunningServiceEnveloped' + "400": + description: Malformed function call, missing field + content: + application/json: + schema: + $ref: '../../shared/schemas/error.yaml#/ErrorEnveloped' + "401": + description: Unauthorized access + content: + application/json: + schema: + $ref: '../../shared/schemas/error.yaml#/ErrorEnveloped' + "404": + description: Service not found + content: + application/json: + schema: + $ref: '../../shared/schemas/error.yaml#/ErrorEnveloped' + "409": + description: A service with the same uuid already exists + content: + application/json: + schema: + $ref: '../../shared/schemas/error.yaml#/ErrorEnveloped' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '../../shared/schemas/error.yaml#/ErrorEnveloped' + + /running_interactive_services/{service_uuid}: + get: + tags: + - users + summary: Succesfully returns if a service with the defined uuid is up and running + description: Succesfully returns if a service with the defined uuid is up and running + operationId: running_interactive_services_get + parameters: + - $ref: '#/components/parameters/ServiceUuid' + responses: + "204": + description: OK service exists and runs + content: + application/json: + schema: + $ref: '../../shared/schemas/response204.yaml#/Response204Enveloped' + "400": + description: Malformed function call, missing field + content: + application/json: + schema: + $ref: '../../shared/schemas/error.yaml#/ErrorEnveloped' + "404": + description: Service not found + content: + application/json: + schema: + $ref: '../../shared/schemas/error.yaml#/ErrorEnveloped' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '../../shared/schemas/error.yaml#/ErrorEnveloped' + delete: + tags: + - users + summary: Stops and removes an interactive service from the oSparc platform + description: Stops and removes an interactive service from the oSparc platform + operationId: running_interactive_services_delete + parameters: + - $ref: '#/components/parameters/ServiceUuid' + responses: + "204": + description: Succesfully stopped and removed the service from the oSparc platform + content: + application/json: + schema: + $ref: '../../shared/schemas/response204.yaml#/Response204Enveloped' + "400": + description: Malformed function call, missing field + content: + application/json: + schema: + $ref: '../../shared/schemas/error.yaml#/ErrorEnveloped' + "404": + description: Service not found + content: + application/json: + schema: + $ref: '../../shared/schemas/error.yaml#/ErrorEnveloped' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '../../shared/schemas/error.yaml#/ErrorEnveloped' + +components: + parameters: + AssignmentUuid: + in: query + name: service_uuid + description: The uuid to assign the service with + required: true + schema: + type: string + format: uuid + example: 123e4567-e89b-12d3-a456-426655440000 + + ServiceKeyPath: + in: path + name: service_key + description: The key (url) of the service + required: true + schema: + type: string + format: url + example: simcore/services/dynamic/3d-viewer + + ServiceKey: + in: query + name: service_key + description: The key (url) of the service + required: true + schema: + type: string + format: url + example: simcore/services/dynamic/3d-viewer + + ServiceType: + in: query + name: service_type + description: | + The service type: + * computational - a computational service + * interactive - an interactive service + required: false + schema: + type: string + enum: + - computational + - interactive + example: computational + + ServiceUuid: + in: path + name: service_uuid + description: The uuid of the service + required: true + schema: + type: string + format: uuid + example: 123e4567-e89b-12d3-a456-426655440000 + + ServiceVersionPath: + in: path + name: service_version + description: The tag/version of the service + required: true + schema: + type: string + example: "1.4" + + ServiceVersion: + in: query + name: service_tag + description: The tag/version of the service + required: false + schema: + type: string + example: "1.4" \ No newline at end of file diff --git a/services/director/src/simcore_service_director/oas3/v1/components/schemas/error.yaml b/apis/shared/schemas/error.yaml similarity index 70% rename from services/director/src/simcore_service_director/oas3/v1/components/schemas/error.yaml rename to apis/shared/schemas/error.yaml index caf05016a57..ee927427e74 100644 --- a/services/director/src/simcore_service_director/oas3/v1/components/schemas/error.yaml +++ b/apis/shared/schemas/error.yaml @@ -1,12 +1,17 @@ ErrorEnveloped: type: object + required: + - data + - error properties: - data: - $ref: '#/Error' - status: - type: integer - example: 404 -Error: + data: + type: object + nullable: true + default: null + error: + $ref: '#/ErrorType' + +ErrorType: type: object required: - status diff --git a/services/director/src/simcore_service_director/oas3/v1/components/schemas/health_check.yaml b/apis/shared/schemas/health_check.yaml similarity index 63% rename from services/director/src/simcore_service_director/oas3/v1/components/schemas/health_check.yaml rename to apis/shared/schemas/health_check.yaml index 10f31921708..a7fa9670644 100644 --- a/services/director/src/simcore_service_director/oas3/v1/components/schemas/health_check.yaml +++ b/apis/shared/schemas/health_check.yaml @@ -1,12 +1,17 @@ HealthCheckEnveloped: type: object + required: + - data + - error properties: data: - $ref: '#/HealthCheck' - status: - type: integer - example: 200 -HealthCheck: + $ref: '#/HealthCheckType' + error: + type: object + nullable: true + default: null + +HealthCheckType: type: object properties: name: diff --git a/services/director/src/simcore_service_director/oas3/v1/components/schemas/node-meta-v0.0.1.yaml b/apis/shared/schemas/node-meta-v0.0.1-converted.yaml similarity index 100% rename from services/director/src/simcore_service_director/oas3/v1/components/schemas/node-meta-v0.0.1.yaml rename to apis/shared/schemas/node-meta-v0.0.1-converted.yaml diff --git a/services/director/src/simcore_service_director/oas3/v1/components/schemas/node-meta-v0.0.1.json b/apis/shared/schemas/node-meta-v0.0.1.json similarity index 100% rename from services/director/src/simcore_service_director/oas3/v1/components/schemas/node-meta-v0.0.1.json rename to apis/shared/schemas/node-meta-v0.0.1.json diff --git a/apis/shared/schemas/response204.yaml b/apis/shared/schemas/response204.yaml new file mode 100644 index 00000000000..2ee044fd56a --- /dev/null +++ b/apis/shared/schemas/response204.yaml @@ -0,0 +1,14 @@ +Response204Enveloped: + type: object + required: + - data + - error + properties: + data: + type: object + nullable: true + default: null + error: + type: object + nullable: true + default: null \ No newline at end of file diff --git a/services/director/src/simcore_service_director/oas3/v1/components/schemas/running_service.yaml b/apis/shared/schemas/running_service.yaml similarity index 75% rename from services/director/src/simcore_service_director/oas3/v1/components/schemas/running_service.yaml rename to apis/shared/schemas/running_service.yaml index 00a9303b143..a2ddf984d38 100644 --- a/services/director/src/simcore_service_director/oas3/v1/components/schemas/running_service.yaml +++ b/apis/shared/schemas/running_service.yaml @@ -1,12 +1,17 @@ RunningServiceEnveloped: type: object + required: + - data + - error properties: data: - $ref: '#/RunningService' - status: - type: integer - example: 200 -RunningService: + $ref: '#/RunningServiceType' + error: + type: object + nullable: true + default: null + +RunningServiceType: type: object required: - published_port diff --git a/apis/shared/schemas/services.yaml b/apis/shared/schemas/services.yaml new file mode 100644 index 00000000000..6a4404f5a81 --- /dev/null +++ b/apis/shared/schemas/services.yaml @@ -0,0 +1,15 @@ +ServicesEnveloped: + type: object + required: + - data + - error + properties: + data: + type: array + items: + $ref: './node-meta-v0.0.1-converted.yaml' + error: + type: object + nullable: true + default: null + \ No newline at end of file diff --git a/apis/tests/requirements.txt b/apis/tests/requirements.txt new file mode 100644 index 00000000000..9bdab57edda --- /dev/null +++ b/apis/tests/requirements.txt @@ -0,0 +1,5 @@ +coveralls~=1.3 +jsonschema~=2.6 +openapi_spec_validator +pytest~=3.6 +pytest-cov~=2.5 \ No newline at end of file diff --git a/apis/tests/test_json_schemas.py b/apis/tests/test_json_schemas.py new file mode 100644 index 00000000000..df1cacd0b5c --- /dev/null +++ b/apis/tests/test_json_schemas.py @@ -0,0 +1,25 @@ +import json +from pathlib import Path + +import pytest +from jsonschema import ( + SchemaError, + ValidationError, + validate) + +_API_DIR = Path(__file__).parent.parent + +def validate_individual_schemas(list_of_paths): + for spec_file_path in list_of_paths: + assert spec_file_path.exists() + with spec_file_path.open() as file_ptr: + schema_specs = json.load(file_ptr) + try: + dummy_instance = {} + with pytest.raises(ValidationError, message="Expected a Json schema validation error"): + validate(dummy_instance, schema_specs) + except SchemaError as err: + pytest.fail(err.message) + +def test_valid_individual_json_schemas_specs(): + validate_individual_schemas(_API_DIR.rglob("*.json")) diff --git a/apis/tests/test_openapi_schemas.py b/apis/tests/test_openapi_schemas.py new file mode 100644 index 00000000000..3b2eeb18aa4 --- /dev/null +++ b/apis/tests/test_openapi_schemas.py @@ -0,0 +1,63 @@ +from pathlib import Path + +import pytest +import yaml + +from openapi_spec_validator import validate_spec +from openapi_spec_validator.exceptions import OpenAPIValidationError + +_API_DIR = Path(__file__).parent.parent + + +def correct_schema_local_references(schema_specs): + for key, value in schema_specs.items(): + if isinstance(value, dict): + correct_schema_local_references(value) + elif "$ref" in key: + if str(value).startswith("#/"): + # correct the reference + new_value = str(value).replace("#/", "#/components/schemas/") + schema_specs[key] = new_value + +def add_namespace_for_converted_schemas(schema_specs): + # schemas converted from jsonschema do not have an overarching namespace. + # the openapi validator does not like this + # we use the jsonschema title to create a fake namespace + fake_schema_specs = { + "FakeName": schema_specs + } + return fake_schema_specs + +def validate_individual_schemas(list_of_paths): + fake_openapi_headers = { + "openapi": "3.0.0", + "info":{ + "title": "An include file to define sortable attributes", + "version": "1.0.0" + }, + "paths": {}, + "components": { + "parameters":{}, + "schemas":{} + } + } + + for spec_file_path in list_of_paths: + assert spec_file_path.exists() + # only consider schemas + if not "openapi.yaml" in str(spec_file_path.name) and "schemas" in str(spec_file_path): + with spec_file_path.open() as file_ptr: + schema_specs = yaml.load(file_ptr) + # correct local references + correct_schema_local_references(schema_specs) + if str(spec_file_path).endswith("-converted.yaml"): + schema_specs = add_namespace_for_converted_schemas(schema_specs) + fake_openapi_headers["components"]["schemas"] = schema_specs + try: + validate_spec(fake_openapi_headers, spec_url=spec_file_path.as_uri()) + except OpenAPIValidationError as err: + pytest.fail(err.message) + +def test_valid_individual_openapi_schemas_specs(): + validate_individual_schemas(_API_DIR.rglob("*.yaml")) + validate_individual_schemas(_API_DIR.rglob("*.yml")) diff --git a/apis/tests/test_openapis.py b/apis/tests/test_openapis.py new file mode 100644 index 00000000000..f0dd2c22e1d --- /dev/null +++ b/apis/tests/test_openapis.py @@ -0,0 +1,25 @@ +from pathlib import Path + +import pytest +import yaml + +from openapi_spec_validator import validate_spec +from openapi_spec_validator.exceptions import OpenAPIValidationError + +_API_DIR = Path(__file__).parent.parent + +def validate_openapi_spec(list_of_paths): + for spec_file_path in list_of_paths: + assert spec_file_path.exists() + with spec_file_path.open() as file_ptr: + openapi_specs = yaml.load(file_ptr) + try: + validate_spec(openapi_specs, spec_url=spec_file_path.as_uri()) + except OpenAPIValidationError as err: + pytest.fail(err.message) + +def test_valid_openapi_specs(): + # get all the openapi complete specs + validate_openapi_spec(_API_DIR.rglob("openapi.yaml")) + validate_openapi_spec(_API_DIR.rglob("openapi.yml")) + diff --git a/apis/tests/test_schemas_conventions.py b/apis/tests/test_schemas_conventions.py new file mode 100644 index 00000000000..5df36779e35 --- /dev/null +++ b/apis/tests/test_schemas_conventions.py @@ -0,0 +1,48 @@ +from pathlib import Path + +import yaml + +_API_DIR = Path(__file__).parent.parent + +def test_openapi_envelope_required_fields(): + _REQUIRED_FIELDS = ["error", "data"] + + list_of_openapi_filepaths = _API_DIR.rglob("*.yaml") + for path in list_of_openapi_filepaths: + # skip converted schemas + if str(path).endswith("-converted.yaml"): + continue + + with path.open() as file_stream: + oas_dict = yaml.safe_load(file_stream) + for key, value in oas_dict.items(): + if "Envelope" in key: + assert "required" in value, "field required is missing from {file}".format(file=str(path)) + required_fields = value["required"] + assert "properties" in value, "field properties is missing from {file}".format(file=str(path)) + fields_definitions = value["properties"] + for field in _REQUIRED_FIELDS: + assert field in required_fields, ("field {field} is missing in {file}".format(field=field, file=str(path))) + assert field in fields_definitions, ("field {field} is missing in {file}".format(field=field, file=str(path))) + +def test_openapi_type_name(): + list_of_openapi_filepaths = _API_DIR.rglob("*.yaml") + for path in list_of_openapi_filepaths: + # skip converted schemas + if str(path).endswith("-converted.yaml"): + continue + + with path.open() as file_stream: + oas_dict = yaml.safe_load(file_stream) + + for key, value in oas_dict.items(): + if "Envelope" in key: + assert "properties" in value, ("field properties is missing from {file}".format(file=str(path))) + fields_definitions = value["properties"] + for field_key, field_value in fields_definitions.items(): + data_values = field_value + for data_key, data_value in data_values.items(): + if "$ref" in data_key: + assert str(data_value).endswith("Type"), ("field {field} name is not finishing with Type in {file}".format(field=field_key, file=str(path))) + + diff --git a/packages/director-sdk/codegen.sh b/packages/director-sdk/codegen.sh index 05b1a765317..58d79a2ae82 100644 --- a/packages/director-sdk/codegen.sh +++ b/packages/director-sdk/codegen.sh @@ -1,6 +1,6 @@ #/bin/bash exec ../../scripts/openapi/openapi_codegen.sh \ - -i ../../services/director/src/simcore_service_director/oas3/v1/openapi.yaml \ + -i ../../services/director/src/simcore_service_director/oas3/v0/openapi.yaml \ -o . \ -g python \ -c ./codegen_config.json diff --git a/packages/director-sdk/python/.openapi-generator/VERSION b/packages/director-sdk/python/.openapi-generator/VERSION index 6d94c9c2e12..06eda28ac73 100644 --- a/packages/director-sdk/python/.openapi-generator/VERSION +++ b/packages/director-sdk/python/.openapi-generator/VERSION @@ -1 +1 @@ -3.3.0-SNAPSHOT \ No newline at end of file +3.2.3 \ No newline at end of file diff --git a/packages/director-sdk/python/README.md b/packages/director-sdk/python/README.md index 6723a1ac057..f25fc172a31 100644 --- a/packages/director-sdk/python/README.md +++ b/packages/director-sdk/python/README.md @@ -23,7 +23,7 @@ pip install git+https://github.com/GIT_USER_ID/GIT_REPO_ID.git Then import the package: ```python -import simcore_director_sdk +import simcore_director_sdk ``` ### Setuptools @@ -79,16 +79,16 @@ Class | Method | HTTP request | Description ## Documentation For Models - - [Error](docs/Error.md) - - [ErrorEnveloped](docs/ErrorEnveloped.md) - - [HealthCheck](docs/HealthCheck.md) - - [HealthCheckEnveloped](docs/HealthCheckEnveloped.md) - - [NodeMetaV0](docs/NodeMetaV0.md) - - [Nodemetav0Authors](docs/Nodemetav0Authors.md) - - [Response204Enveloped](docs/Response204Enveloped.md) - - [RunningService](docs/RunningService.md) - - [RunningServiceEnveloped](docs/RunningServiceEnveloped.md) - - [ServicesEnveloped](docs/ServicesEnveloped.md) + - [InlineResponse200](docs/InlineResponse200.md) + - [InlineResponse2001](docs/InlineResponse2001.md) + - [InlineResponse2001Authors](docs/InlineResponse2001Authors.md) + - [InlineResponse200Data](docs/InlineResponse200Data.md) + - [InlineResponse201](docs/InlineResponse201.md) + - [InlineResponse201Data](docs/InlineResponse201Data.md) + - [InlineResponse204](docs/InlineResponse204.md) + - [InlineResponseDefault](docs/InlineResponseDefault.md) + - [InlineResponseDefaultError](docs/InlineResponseDefaultError.md) + - [SimcoreNode](docs/SimcoreNode.md) ## Documentation For Authorization @@ -99,3 +99,5 @@ Class | Method | HTTP request | Description ## Author support@simcore.com + + diff --git a/packages/director-sdk/python/docs/Response204Enveloped.md b/packages/director-sdk/python/docs/InlineResponse200.md similarity index 65% rename from packages/director-sdk/python/docs/Response204Enveloped.md rename to packages/director-sdk/python/docs/InlineResponse200.md index 04978c1ad27..b7f59af1fe5 100644 --- a/packages/director-sdk/python/docs/Response204Enveloped.md +++ b/packages/director-sdk/python/docs/InlineResponse200.md @@ -1,10 +1,10 @@ -# Response204Enveloped +# InlineResponse200 ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**data** | **str** | | [optional] [default to 'null'] -**status** | **int** | | [optional] [default to 204] +**data** | [**InlineResponse200Data**](InlineResponse200Data.md) | | [optional] +**error** | **object** | | [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) diff --git a/packages/director-sdk/python/docs/RunningServiceEnveloped.md b/packages/director-sdk/python/docs/InlineResponse2001.md similarity index 68% rename from packages/director-sdk/python/docs/RunningServiceEnveloped.md rename to packages/director-sdk/python/docs/InlineResponse2001.md index e39831eb918..1f3ecdd141c 100644 --- a/packages/director-sdk/python/docs/RunningServiceEnveloped.md +++ b/packages/director-sdk/python/docs/InlineResponse2001.md @@ -1,10 +1,10 @@ -# RunningServiceEnveloped +# InlineResponse2001 ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**data** | [**RunningService**](RunningService.md) | | [optional] -**status** | **int** | | [optional] +**data** | [**list[SimcoreNode]**](SimcoreNode.md) | | [optional] +**error** | **object** | | [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) diff --git a/packages/director-sdk/python/docs/Nodemetav0Authors.md b/packages/director-sdk/python/docs/InlineResponse2001Authors.md similarity index 94% rename from packages/director-sdk/python/docs/Nodemetav0Authors.md rename to packages/director-sdk/python/docs/InlineResponse2001Authors.md index 41e48a7146f..757de0983dd 100644 --- a/packages/director-sdk/python/docs/Nodemetav0Authors.md +++ b/packages/director-sdk/python/docs/InlineResponse2001Authors.md @@ -1,11 +1,11 @@ -# Nodemetav0Authors +# InlineResponse2001Authors ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**name** | **str** | Name of the author | [optional] -**email** | **str** | Email address | [optional] **affiliation** | **str** | Affiliation of the author | [optional] +**email** | **str** | Email address | [optional] +**name** | **str** | Name of the author | [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) diff --git a/packages/director-sdk/python/docs/HealthCheck.md b/packages/director-sdk/python/docs/InlineResponse200Data.md similarity index 94% rename from packages/director-sdk/python/docs/HealthCheck.md rename to packages/director-sdk/python/docs/InlineResponse200Data.md index 3309fefbd0b..cf8874e158c 100644 --- a/packages/director-sdk/python/docs/HealthCheck.md +++ b/packages/director-sdk/python/docs/InlineResponse200Data.md @@ -1,11 +1,11 @@ -# HealthCheck +# InlineResponse200Data ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- +**api_version** | **str** | | [optional] **name** | **str** | | [optional] **status** | **str** | | [optional] -**api_version** | **str** | | [optional] **version** | **str** | | [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) diff --git a/packages/director-sdk/python/docs/HealthCheckEnveloped.md b/packages/director-sdk/python/docs/InlineResponse201.md similarity index 65% rename from packages/director-sdk/python/docs/HealthCheckEnveloped.md rename to packages/director-sdk/python/docs/InlineResponse201.md index 926a484e05c..746f650f9e3 100644 --- a/packages/director-sdk/python/docs/HealthCheckEnveloped.md +++ b/packages/director-sdk/python/docs/InlineResponse201.md @@ -1,10 +1,10 @@ -# HealthCheckEnveloped +# InlineResponse201 ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**data** | [**HealthCheck**](HealthCheck.md) | | [optional] -**status** | **int** | | [optional] +**data** | [**InlineResponse201Data**](InlineResponse201Data.md) | | [optional] +**error** | **object** | | [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) diff --git a/packages/director-sdk/python/docs/RunningService.md b/packages/director-sdk/python/docs/InlineResponse201Data.md similarity index 79% rename from packages/director-sdk/python/docs/RunningService.md rename to packages/director-sdk/python/docs/InlineResponse201Data.md index ba25b7fe899..4f5c5f085c2 100644 --- a/packages/director-sdk/python/docs/RunningService.md +++ b/packages/director-sdk/python/docs/InlineResponse201Data.md @@ -1,10 +1,12 @@ -# RunningService +# InlineResponse201Data ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**published_port** | **int** | The ports where the service provides its interface | -**entry_point** | **str** | The entry point where the service provides its interface if specified | [optional] -**service_uuid** | **str** | The UUID attached to this service | +**entry_point** | **str** | The entry point where the service provides its interface if specified | [optional] +**published_port** | **int** | The ports where the service provides its interface | [optional] +**service_uuid** | **str** | The UUID attached to this service | [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) + + diff --git a/packages/director-sdk/python/docs/ErrorEnveloped.md b/packages/director-sdk/python/docs/InlineResponse204.md similarity index 72% rename from packages/director-sdk/python/docs/ErrorEnveloped.md rename to packages/director-sdk/python/docs/InlineResponse204.md index 77ef45a3b95..e8c01d0e67f 100644 --- a/packages/director-sdk/python/docs/ErrorEnveloped.md +++ b/packages/director-sdk/python/docs/InlineResponse204.md @@ -1,10 +1,10 @@ -# ErrorEnveloped +# InlineResponse204 ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**data** | [**Error**](Error.md) | | [optional] -**status** | **int** | | [optional] +**data** | **object** | | [optional] +**error** | **object** | | [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) diff --git a/packages/director-sdk/python/docs/InlineResponseDefault.md b/packages/director-sdk/python/docs/InlineResponseDefault.md new file mode 100644 index 00000000000..561781cffba --- /dev/null +++ b/packages/director-sdk/python/docs/InlineResponseDefault.md @@ -0,0 +1,11 @@ +# InlineResponseDefault + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**data** | **object** | | [optional] +**error** | [**InlineResponseDefaultError**](InlineResponseDefaultError.md) | | [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) + + diff --git a/packages/director-sdk/python/docs/Error.md b/packages/director-sdk/python/docs/InlineResponseDefaultError.md similarity index 71% rename from packages/director-sdk/python/docs/Error.md rename to packages/director-sdk/python/docs/InlineResponseDefaultError.md index 32eb1063ba9..2b9cd5bc3f2 100644 --- a/packages/director-sdk/python/docs/Error.md +++ b/packages/director-sdk/python/docs/InlineResponseDefaultError.md @@ -1,11 +1,11 @@ -# Error +# InlineResponseDefaultError ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**message** | **str** | Error message | **errors** | **list[object]** | | [optional] -**status** | **int** | Error code | +**message** | **str** | Error message | [optional] +**status** | **int** | Error code | [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) diff --git a/packages/director-sdk/python/docs/ServicesEnveloped.md b/packages/director-sdk/python/docs/ServicesEnveloped.md deleted file mode 100644 index 26ea5cb74fb..00000000000 --- a/packages/director-sdk/python/docs/ServicesEnveloped.md +++ /dev/null @@ -1,11 +0,0 @@ -# ServicesEnveloped - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**data** | [**list[NodeMetaV0]**](NodeMetaV0.md) | | [optional] -**status** | **int** | | [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) - - diff --git a/packages/director-sdk/python/docs/NodeMetaV0.md b/packages/director-sdk/python/docs/SimcoreNode.md similarity index 58% rename from packages/director-sdk/python/docs/NodeMetaV0.md rename to packages/director-sdk/python/docs/SimcoreNode.md index 600a528f6d1..f61c2c16151 100644 --- a/packages/director-sdk/python/docs/NodeMetaV0.md +++ b/packages/director-sdk/python/docs/SimcoreNode.md @@ -1,17 +1,17 @@ -# NodeMetaV0 +# SimcoreNode ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**key** | **str** | distinctive name for the node based on the docker registry path | -**version** | **str** | semantic version number | -**type** | **str** | service type | -**name** | **str** | short, human readable name for the node | -**description** | **str** | human readable description of the purpose of the node | -**authors** | [**list[Nodemetav0Authors]**](Nodemetav0Authors.md) | | -**contact** | **str** | email to correspond to the authors about the node | -**inputs** | **object** | definition of the inputs of this node | -**outputs** | **object** | definition of the outputs of this node | +**authors** | [**list[InlineResponse2001Authors]**](InlineResponse2001Authors.md) | | [optional] +**contact** | **str** | email to correspond to the authors about the node | [optional] +**description** | **str** | human readable description of the purpose of the node | [optional] +**inputs** | **object** | definition of the inputs of this node | [optional] +**key** | **str** | distinctive name for the node based on the docker registry path | [optional] +**name** | **str** | short, human readable name for the node | [optional] +**outputs** | **object** | definition of the outputs of this node | [optional] +**type** | **str** | service type | [optional] +**version** | **str** | semantic version number | [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) diff --git a/packages/director-sdk/python/docs/UsersApi.md b/packages/director-sdk/python/docs/UsersApi.md index ee9395b5687..e9ea1d8dcf5 100644 --- a/packages/director-sdk/python/docs/UsersApi.md +++ b/packages/director-sdk/python/docs/UsersApi.md @@ -13,7 +13,7 @@ Method | HTTP request | Description # **root_get** -> HealthCheckEnveloped root_get() +> InlineResponse200 root_get() Service health-check endpoint @@ -43,7 +43,7 @@ This endpoint does not need any parameter. ### Return type -[**HealthCheckEnveloped**](HealthCheckEnveloped.md) +[**InlineResponse200**](InlineResponse200.md) ### Authorization @@ -57,7 +57,7 @@ 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) # **running_interactive_services_delete** -> Response204Enveloped running_interactive_services_delete(service_uuid) +> InlineResponse204 running_interactive_services_delete(service_uuid) Stops and removes an interactive service from the oSparc platform @@ -87,11 +87,11 @@ except ApiException as e: Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **service_uuid** | [**str**](.md)| The uuid of the service | + **service_uuid** | [**str**](.md)| The uuid of the service | ### Return type -[**Response204Enveloped**](Response204Enveloped.md) +[**InlineResponse204**](InlineResponse204.md) ### Authorization @@ -105,7 +105,7 @@ 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) # **running_interactive_services_get** -> Response204Enveloped running_interactive_services_get(service_uuid) +> InlineResponse204 running_interactive_services_get(service_uuid) Succesfully returns if a service with the defined uuid is up and running @@ -135,11 +135,11 @@ except ApiException as e: Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **service_uuid** | [**str**](.md)| The uuid of the service | + **service_uuid** | [**str**](.md)| The uuid of the service | ### Return type -[**Response204Enveloped**](Response204Enveloped.md) +[**InlineResponse204**](InlineResponse204.md) ### Authorization @@ -153,7 +153,7 @@ 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) # **running_interactive_services_post** -> RunningServiceEnveloped running_interactive_services_post(service_key, service_uuid, service_tag=service_tag) +> InlineResponse201 running_interactive_services_post(service_key, service_uuid, service_tag=service_tag) Starts an interactive service in the oSparc platform and returns its entrypoint @@ -185,13 +185,13 @@ except ApiException as e: Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **service_key** | **str**| The key (url) of the service | - **service_uuid** | [**str**](.md)| The uuid to assign the service with | - **service_tag** | **str**| The tag/version of the service | [optional] + **service_key** | **str**| The key (url) of the service | + **service_uuid** | [**str**](.md)| The uuid to assign the service with | + **service_tag** | **str**| The tag/version of the service | [optional] ### Return type -[**RunningServiceEnveloped**](RunningServiceEnveloped.md) +[**InlineResponse201**](InlineResponse201.md) ### Authorization @@ -205,7 +205,7 @@ 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) # **services_by_key_version_get** -> ServicesEnveloped services_by_key_version_get(service_key, service_version) +> InlineResponse2001 services_by_key_version_get(service_key, service_version) Returns details of the selected service if available in the oSparc platform @@ -236,12 +236,12 @@ except ApiException as e: Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **service_key** | **str**| The key (url) of the service | - **service_version** | **str**| The tag/version of the service | + **service_key** | **str**| The key (url) of the service | + **service_version** | **str**| The tag/version of the service | ### Return type -[**ServicesEnveloped**](ServicesEnveloped.md) +[**InlineResponse2001**](InlineResponse2001.md) ### Authorization @@ -255,7 +255,7 @@ 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) # **services_get** -> ServicesEnveloped services_get(service_type=service_type) +> InlineResponse2001 services_get(service_type=service_type) Lists available services in the oSparc platform @@ -285,11 +285,11 @@ except ApiException as e: Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **service_type** | **str**| The service type: * computational - a computational service * interactive - an interactive service | [optional] + **service_type** | **str**| The service type: * computational - a computational service * interactive - an interactive service | [optional] ### Return type -[**ServicesEnveloped**](ServicesEnveloped.md) +[**InlineResponse2001**](InlineResponse2001.md) ### Authorization @@ -301,3 +301,4 @@ No authorization required - **Accept**: application/json [[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) + diff --git a/packages/director-sdk/python/simcore_director_sdk/__init__.py b/packages/director-sdk/python/simcore_director_sdk/__init__.py index 620ac04ef6f..7a090197906 100644 --- a/packages/director-sdk/python/simcore_director_sdk/__init__.py +++ b/packages/director-sdk/python/simcore_director_sdk/__init__.py @@ -24,13 +24,13 @@ from simcore_director_sdk.api_client import ApiClient from simcore_director_sdk.configuration import Configuration # import models into sdk package -from simcore_director_sdk.models.error import Error -from simcore_director_sdk.models.error_enveloped import ErrorEnveloped -from simcore_director_sdk.models.health_check import HealthCheck -from simcore_director_sdk.models.health_check_enveloped import HealthCheckEnveloped -from simcore_director_sdk.models.node_meta_v0 import NodeMetaV0 -from simcore_director_sdk.models.nodemetav0_authors import Nodemetav0Authors -from simcore_director_sdk.models.response204_enveloped import Response204Enveloped -from simcore_director_sdk.models.running_service import RunningService -from simcore_director_sdk.models.running_service_enveloped import RunningServiceEnveloped -from simcore_director_sdk.models.services_enveloped import ServicesEnveloped +from simcore_director_sdk.models.inline_response200 import InlineResponse200 +from simcore_director_sdk.models.inline_response2001 import InlineResponse2001 +from simcore_director_sdk.models.inline_response2001_authors import InlineResponse2001Authors +from simcore_director_sdk.models.inline_response200_data import InlineResponse200Data +from simcore_director_sdk.models.inline_response201 import InlineResponse201 +from simcore_director_sdk.models.inline_response201_data import InlineResponse201Data +from simcore_director_sdk.models.inline_response204 import InlineResponse204 +from simcore_director_sdk.models.inline_response_default import InlineResponseDefault +from simcore_director_sdk.models.inline_response_default_error import InlineResponseDefaultError +from simcore_director_sdk.models.simcore_node import SimcoreNode diff --git a/packages/director-sdk/python/simcore_director_sdk/api/users_api.py b/packages/director-sdk/python/simcore_director_sdk/api/users_api.py index 4b427770fb3..d53e2e00940 100644 --- a/packages/director-sdk/python/simcore_director_sdk/api/users_api.py +++ b/packages/director-sdk/python/simcore_director_sdk/api/users_api.py @@ -43,7 +43,7 @@ def root_get(self, **kwargs): # noqa: E501 >>> result = thread.get() :param async_req bool - :return: HealthCheckEnveloped + :return: InlineResponse200 If the method is called asynchronously, returns the request thread. """ @@ -64,7 +64,7 @@ def root_get_with_http_info(self, **kwargs): # noqa: E501 >>> result = thread.get() :param async_req bool - :return: HealthCheckEnveloped + :return: InlineResponse200 If the method is called asynchronously, returns the request thread. """ @@ -113,7 +113,7 @@ def root_get_with_http_info(self, **kwargs): # noqa: E501 body=body_params, post_params=form_params, files=local_var_files, - response_type='HealthCheckEnveloped', # noqa: E501 + response_type='InlineResponse200', # noqa: E501 auth_settings=auth_settings, async_req=local_var_params.get('async_req'), _return_http_data_only=local_var_params.get('_return_http_data_only'), # noqa: E501 @@ -132,7 +132,7 @@ def running_interactive_services_delete(self, service_uuid, **kwargs): # noqa: :param async_req bool :param str service_uuid: The uuid of the service (required) - :return: Response204Enveloped + :return: InlineResponse204 If the method is called asynchronously, returns the request thread. """ @@ -154,7 +154,7 @@ def running_interactive_services_delete_with_http_info(self, service_uuid, **kwa :param async_req bool :param str service_uuid: The uuid of the service (required) - :return: Response204Enveloped + :return: InlineResponse204 If the method is called asynchronously, returns the request thread. """ @@ -209,7 +209,7 @@ def running_interactive_services_delete_with_http_info(self, service_uuid, **kwa body=body_params, post_params=form_params, files=local_var_files, - response_type='Response204Enveloped', # noqa: E501 + response_type='InlineResponse204', # noqa: E501 auth_settings=auth_settings, async_req=local_var_params.get('async_req'), _return_http_data_only=local_var_params.get('_return_http_data_only'), # noqa: E501 @@ -228,7 +228,7 @@ def running_interactive_services_get(self, service_uuid, **kwargs): # noqa: E50 :param async_req bool :param str service_uuid: The uuid of the service (required) - :return: Response204Enveloped + :return: InlineResponse204 If the method is called asynchronously, returns the request thread. """ @@ -250,7 +250,7 @@ def running_interactive_services_get_with_http_info(self, service_uuid, **kwargs :param async_req bool :param str service_uuid: The uuid of the service (required) - :return: Response204Enveloped + :return: InlineResponse204 If the method is called asynchronously, returns the request thread. """ @@ -305,7 +305,7 @@ def running_interactive_services_get_with_http_info(self, service_uuid, **kwargs body=body_params, post_params=form_params, files=local_var_files, - response_type='Response204Enveloped', # noqa: E501 + response_type='InlineResponse204', # noqa: E501 auth_settings=auth_settings, async_req=local_var_params.get('async_req'), _return_http_data_only=local_var_params.get('_return_http_data_only'), # noqa: E501 @@ -326,7 +326,7 @@ def running_interactive_services_post(self, service_key, service_uuid, **kwargs) :param str service_key: The key (url) of the service (required) :param str service_uuid: The uuid to assign the service with (required) :param str service_tag: The tag/version of the service - :return: RunningServiceEnveloped + :return: InlineResponse201 If the method is called asynchronously, returns the request thread. """ @@ -350,7 +350,7 @@ def running_interactive_services_post_with_http_info(self, service_key, service_ :param str service_key: The key (url) of the service (required) :param str service_uuid: The uuid to assign the service with (required) :param str service_tag: The tag/version of the service - :return: RunningServiceEnveloped + :return: InlineResponse201 If the method is called asynchronously, returns the request thread. """ @@ -413,7 +413,7 @@ def running_interactive_services_post_with_http_info(self, service_key, service_ body=body_params, post_params=form_params, files=local_var_files, - response_type='RunningServiceEnveloped', # noqa: E501 + response_type='InlineResponse201', # noqa: E501 auth_settings=auth_settings, async_req=local_var_params.get('async_req'), _return_http_data_only=local_var_params.get('_return_http_data_only'), # noqa: E501 @@ -433,7 +433,7 @@ def services_by_key_version_get(self, service_key, service_version, **kwargs): :param async_req bool :param str service_key: The key (url) of the service (required) :param str service_version: The tag/version of the service (required) - :return: ServicesEnveloped + :return: InlineResponse2001 If the method is called asynchronously, returns the request thread. """ @@ -456,7 +456,7 @@ def services_by_key_version_get_with_http_info(self, service_key, service_versio :param async_req bool :param str service_key: The key (url) of the service (required) :param str service_version: The tag/version of the service (required) - :return: ServicesEnveloped + :return: InlineResponse2001 If the method is called asynchronously, returns the request thread. """ @@ -517,7 +517,7 @@ def services_by_key_version_get_with_http_info(self, service_key, service_versio body=body_params, post_params=form_params, files=local_var_files, - response_type='ServicesEnveloped', # noqa: E501 + response_type='InlineResponse2001', # noqa: E501 auth_settings=auth_settings, async_req=local_var_params.get('async_req'), _return_http_data_only=local_var_params.get('_return_http_data_only'), # noqa: E501 @@ -535,8 +535,8 @@ def services_get(self, **kwargs): # noqa: E501 >>> result = thread.get() :param async_req bool - :param str service_type: The service type: * computational - a computational service * interactive - an interactive service - :return: ServicesEnveloped + :param str service_type: The service type: * computational - a computational service * interactive - an interactive service + :return: InlineResponse2001 If the method is called asynchronously, returns the request thread. """ @@ -557,8 +557,8 @@ def services_get_with_http_info(self, **kwargs): # noqa: E501 >>> result = thread.get() :param async_req bool - :param str service_type: The service type: * computational - a computational service * interactive - an interactive service - :return: ServicesEnveloped + :param str service_type: The service type: * computational - a computational service * interactive - an interactive service + :return: InlineResponse2001 If the method is called asynchronously, returns the request thread. """ @@ -609,7 +609,7 @@ def services_get_with_http_info(self, **kwargs): # noqa: E501 body=body_params, post_params=form_params, files=local_var_files, - response_type='ServicesEnveloped', # noqa: E501 + response_type='InlineResponse2001', # noqa: E501 auth_settings=auth_settings, async_req=local_var_params.get('async_req'), _return_http_data_only=local_var_params.get('_return_http_data_only'), # noqa: E501 diff --git a/packages/director-sdk/python/simcore_director_sdk/models/__init__.py b/packages/director-sdk/python/simcore_director_sdk/models/__init__.py index 32f7b7b9c87..9995047a8f6 100644 --- a/packages/director-sdk/python/simcore_director_sdk/models/__init__.py +++ b/packages/director-sdk/python/simcore_director_sdk/models/__init__.py @@ -15,13 +15,13 @@ from __future__ import absolute_import # import models into model package -from simcore_director_sdk.models.error import Error -from simcore_director_sdk.models.error_enveloped import ErrorEnveloped -from simcore_director_sdk.models.health_check import HealthCheck -from simcore_director_sdk.models.health_check_enveloped import HealthCheckEnveloped -from simcore_director_sdk.models.node_meta_v0 import NodeMetaV0 -from simcore_director_sdk.models.nodemetav0_authors import Nodemetav0Authors -from simcore_director_sdk.models.response204_enveloped import Response204Enveloped -from simcore_director_sdk.models.running_service import RunningService -from simcore_director_sdk.models.running_service_enveloped import RunningServiceEnveloped -from simcore_director_sdk.models.services_enveloped import ServicesEnveloped +from simcore_director_sdk.models.inline_response200 import InlineResponse200 +from simcore_director_sdk.models.inline_response2001 import InlineResponse2001 +from simcore_director_sdk.models.inline_response2001_authors import InlineResponse2001Authors +from simcore_director_sdk.models.inline_response200_data import InlineResponse200Data +from simcore_director_sdk.models.inline_response201 import InlineResponse201 +from simcore_director_sdk.models.inline_response201_data import InlineResponse201Data +from simcore_director_sdk.models.inline_response204 import InlineResponse204 +from simcore_director_sdk.models.inline_response_default import InlineResponseDefault +from simcore_director_sdk.models.inline_response_default_error import InlineResponseDefaultError +from simcore_director_sdk.models.simcore_node import SimcoreNode diff --git a/packages/director-sdk/python/simcore_director_sdk/models/services_enveloped.py b/packages/director-sdk/python/simcore_director_sdk/models/inline_response200.py similarity index 68% rename from packages/director-sdk/python/simcore_director_sdk/models/services_enveloped.py rename to packages/director-sdk/python/simcore_director_sdk/models/inline_response200.py index 9863d17a202..8030f6f7b10 100644 --- a/packages/director-sdk/python/simcore_director_sdk/models/services_enveloped.py +++ b/packages/director-sdk/python/simcore_director_sdk/models/inline_response200.py @@ -17,7 +17,7 @@ import six -class ServicesEnveloped(object): +class InlineResponse200(object): """NOTE: This class is auto generated by OpenAPI Generator. Ref: https://openapi-generator.tech @@ -32,68 +32,68 @@ class ServicesEnveloped(object): and the value is json key in definition. """ openapi_types = { - 'data': 'list[NodeMetaV0]', - 'status': 'int' + 'data': 'InlineResponse200Data', + 'error': 'object' } attribute_map = { 'data': 'data', - 'status': 'status' + 'error': 'error' } - def __init__(self, data=None, status=None): # noqa: E501 - """ServicesEnveloped - a model defined in OpenAPI""" # noqa: E501 + def __init__(self, data=None, error=None): # noqa: E501 + """InlineResponse200 - a model defined in OpenAPI""" # noqa: E501 self._data = None - self._status = None + self._error = None self.discriminator = None if data is not None: self.data = data - if status is not None: - self.status = status + if error is not None: + self.error = error @property def data(self): - """Gets the data of this ServicesEnveloped. # noqa: E501 + """Gets the data of this InlineResponse200. # noqa: E501 - :return: The data of this ServicesEnveloped. # noqa: E501 - :rtype: list[NodeMetaV0] + :return: The data of this InlineResponse200. # noqa: E501 + :rtype: InlineResponse200Data """ return self._data @data.setter def data(self, data): - """Sets the data of this ServicesEnveloped. + """Sets the data of this InlineResponse200. - :param data: The data of this ServicesEnveloped. # noqa: E501 - :type: list[NodeMetaV0] + :param data: The data of this InlineResponse200. # noqa: E501 + :type: InlineResponse200Data """ self._data = data @property - def status(self): - """Gets the status of this ServicesEnveloped. # noqa: E501 + def error(self): + """Gets the error of this InlineResponse200. # noqa: E501 - :return: The status of this ServicesEnveloped. # noqa: E501 - :rtype: int + :return: The error of this InlineResponse200. # noqa: E501 + :rtype: object """ - return self._status + return self._error - @status.setter - def status(self, status): - """Sets the status of this ServicesEnveloped. + @error.setter + def error(self, error): + """Sets the error of this InlineResponse200. - :param status: The status of this ServicesEnveloped. # noqa: E501 - :type: int + :param error: The error of this InlineResponse200. # noqa: E501 + :type: object """ - self._status = status + self._error = error def to_dict(self): """Returns the model properties as a dict""" @@ -129,7 +129,7 @@ def __repr__(self): def __eq__(self, other): """Returns true if both objects are equal""" - if not isinstance(other, ServicesEnveloped): + if not isinstance(other, InlineResponse200): return False return self.__dict__ == other.__dict__ diff --git a/packages/director-sdk/python/simcore_director_sdk/models/response204_enveloped.py b/packages/director-sdk/python/simcore_director_sdk/models/inline_response2001.py similarity index 68% rename from packages/director-sdk/python/simcore_director_sdk/models/response204_enveloped.py rename to packages/director-sdk/python/simcore_director_sdk/models/inline_response2001.py index 9a9d97a2cf7..74f2999a0d1 100644 --- a/packages/director-sdk/python/simcore_director_sdk/models/response204_enveloped.py +++ b/packages/director-sdk/python/simcore_director_sdk/models/inline_response2001.py @@ -17,7 +17,7 @@ import six -class Response204Enveloped(object): +class InlineResponse2001(object): """NOTE: This class is auto generated by OpenAPI Generator. Ref: https://openapi-generator.tech @@ -32,68 +32,68 @@ class Response204Enveloped(object): and the value is json key in definition. """ openapi_types = { - 'data': 'str', - 'status': 'int' + 'data': 'list[SimcoreNode]', + 'error': 'object' } attribute_map = { 'data': 'data', - 'status': 'status' + 'error': 'error' } - def __init__(self, data='null', status=204): # noqa: E501 - """Response204Enveloped - a model defined in OpenAPI""" # noqa: E501 + def __init__(self, data=None, error=None): # noqa: E501 + """InlineResponse2001 - a model defined in OpenAPI""" # noqa: E501 self._data = None - self._status = None + self._error = None self.discriminator = None if data is not None: self.data = data - if status is not None: - self.status = status + if error is not None: + self.error = error @property def data(self): - """Gets the data of this Response204Enveloped. # noqa: E501 + """Gets the data of this InlineResponse2001. # noqa: E501 - :return: The data of this Response204Enveloped. # noqa: E501 - :rtype: str + :return: The data of this InlineResponse2001. # noqa: E501 + :rtype: list[SimcoreNode] """ return self._data @data.setter def data(self, data): - """Sets the data of this Response204Enveloped. + """Sets the data of this InlineResponse2001. - :param data: The data of this Response204Enveloped. # noqa: E501 - :type: str + :param data: The data of this InlineResponse2001. # noqa: E501 + :type: list[SimcoreNode] """ self._data = data @property - def status(self): - """Gets the status of this Response204Enveloped. # noqa: E501 + def error(self): + """Gets the error of this InlineResponse2001. # noqa: E501 - :return: The status of this Response204Enveloped. # noqa: E501 - :rtype: int + :return: The error of this InlineResponse2001. # noqa: E501 + :rtype: object """ - return self._status + return self._error - @status.setter - def status(self, status): - """Sets the status of this Response204Enveloped. + @error.setter + def error(self, error): + """Sets the error of this InlineResponse2001. - :param status: The status of this Response204Enveloped. # noqa: E501 - :type: int + :param error: The error of this InlineResponse2001. # noqa: E501 + :type: object """ - self._status = status + self._error = error def to_dict(self): """Returns the model properties as a dict""" @@ -129,7 +129,7 @@ def __repr__(self): def __eq__(self, other): """Returns true if both objects are equal""" - if not isinstance(other, Response204Enveloped): + if not isinstance(other, InlineResponse2001): return False return self.__dict__ == other.__dict__ diff --git a/packages/director-sdk/python/simcore_director_sdk/models/nodemetav0_authors.py b/packages/director-sdk/python/simcore_director_sdk/models/inline_response2001_authors.py similarity index 73% rename from packages/director-sdk/python/simcore_director_sdk/models/nodemetav0_authors.py rename to packages/director-sdk/python/simcore_director_sdk/models/inline_response2001_authors.py index bf6a13bf530..fd1ce470889 100644 --- a/packages/director-sdk/python/simcore_director_sdk/models/nodemetav0_authors.py +++ b/packages/director-sdk/python/simcore_director_sdk/models/inline_response2001_authors.py @@ -17,7 +17,7 @@ import six -class Nodemetav0Authors(object): +class InlineResponse2001Authors(object): """NOTE: This class is auto generated by OpenAPI Generator. Ref: https://openapi-generator.tech @@ -32,100 +32,100 @@ class Nodemetav0Authors(object): and the value is json key in definition. """ openapi_types = { - 'name': 'str', + 'affiliation': 'str', 'email': 'str', - 'affiliation': 'str' + 'name': 'str' } attribute_map = { - 'name': 'name', + 'affiliation': 'affiliation', 'email': 'email', - 'affiliation': 'affiliation' + 'name': 'name' } - def __init__(self, name=None, email=None, affiliation=None): # noqa: E501 - """Nodemetav0Authors - a model defined in OpenAPI""" # noqa: E501 + def __init__(self, affiliation=None, email=None, name=None): # noqa: E501 + """InlineResponse2001Authors - a model defined in OpenAPI""" # noqa: E501 - self._name = None - self._email = None self._affiliation = None + self._email = None + self._name = None self.discriminator = None - if name is not None: - self.name = name - if email is not None: - self.email = email if affiliation is not None: self.affiliation = affiliation + if email is not None: + self.email = email + if name is not None: + self.name = name @property - def name(self): - """Gets the name of this Nodemetav0Authors. # noqa: E501 + def affiliation(self): + """Gets the affiliation of this InlineResponse2001Authors. # noqa: E501 - Name of the author # noqa: E501 + Affiliation of the author # noqa: E501 - :return: The name of this Nodemetav0Authors. # noqa: E501 + :return: The affiliation of this InlineResponse2001Authors. # noqa: E501 :rtype: str """ - return self._name + return self._affiliation - @name.setter - def name(self, name): - """Sets the name of this Nodemetav0Authors. + @affiliation.setter + def affiliation(self, affiliation): + """Sets the affiliation of this InlineResponse2001Authors. - Name of the author # noqa: E501 + Affiliation of the author # noqa: E501 - :param name: The name of this Nodemetav0Authors. # noqa: E501 + :param affiliation: The affiliation of this InlineResponse2001Authors. # noqa: E501 :type: str """ - self._name = name + self._affiliation = affiliation @property def email(self): - """Gets the email of this Nodemetav0Authors. # noqa: E501 + """Gets the email of this InlineResponse2001Authors. # noqa: E501 Email address # noqa: E501 - :return: The email of this Nodemetav0Authors. # noqa: E501 + :return: The email of this InlineResponse2001Authors. # noqa: E501 :rtype: str """ return self._email @email.setter def email(self, email): - """Sets the email of this Nodemetav0Authors. + """Sets the email of this InlineResponse2001Authors. Email address # noqa: E501 - :param email: The email of this Nodemetav0Authors. # noqa: E501 + :param email: The email of this InlineResponse2001Authors. # noqa: E501 :type: str """ self._email = email @property - def affiliation(self): - """Gets the affiliation of this Nodemetav0Authors. # noqa: E501 + def name(self): + """Gets the name of this InlineResponse2001Authors. # noqa: E501 - Affiliation of the author # noqa: E501 + Name of the author # noqa: E501 - :return: The affiliation of this Nodemetav0Authors. # noqa: E501 + :return: The name of this InlineResponse2001Authors. # noqa: E501 :rtype: str """ - return self._affiliation + return self._name - @affiliation.setter - def affiliation(self, affiliation): - """Sets the affiliation of this Nodemetav0Authors. + @name.setter + def name(self, name): + """Sets the name of this InlineResponse2001Authors. - Affiliation of the author # noqa: E501 + Name of the author # noqa: E501 - :param affiliation: The affiliation of this Nodemetav0Authors. # noqa: E501 + :param name: The name of this InlineResponse2001Authors. # noqa: E501 :type: str """ - self._affiliation = affiliation + self._name = name def to_dict(self): """Returns the model properties as a dict""" @@ -161,7 +161,7 @@ def __repr__(self): def __eq__(self, other): """Returns true if both objects are equal""" - if not isinstance(other, Nodemetav0Authors): + if not isinstance(other, InlineResponse2001Authors): return False return self.__dict__ == other.__dict__ diff --git a/packages/director-sdk/python/simcore_director_sdk/models/health_check.py b/packages/director-sdk/python/simcore_director_sdk/models/inline_response200_data.py similarity index 72% rename from packages/director-sdk/python/simcore_director_sdk/models/health_check.py rename to packages/director-sdk/python/simcore_director_sdk/models/inline_response200_data.py index 5e9a3916907..ff7a590e424 100644 --- a/packages/director-sdk/python/simcore_director_sdk/models/health_check.py +++ b/packages/director-sdk/python/simcore_director_sdk/models/inline_response200_data.py @@ -17,7 +17,7 @@ import six -class HealthCheck(object): +class InlineResponse200Data(object): """NOTE: This class is auto generated by OpenAPI Generator. Ref: https://openapi-generator.tech @@ -32,116 +32,116 @@ class HealthCheck(object): and the value is json key in definition. """ openapi_types = { + 'api_version': 'str', 'name': 'str', 'status': 'str', - 'api_version': 'str', 'version': 'str' } attribute_map = { + 'api_version': 'api_version', 'name': 'name', 'status': 'status', - 'api_version': 'api_version', 'version': 'version' } - def __init__(self, name=None, status=None, api_version=None, version=None): # noqa: E501 - """HealthCheck - a model defined in OpenAPI""" # noqa: E501 + def __init__(self, api_version=None, name=None, status=None, version=None): # noqa: E501 + """InlineResponse200Data - a model defined in OpenAPI""" # noqa: E501 + self._api_version = None self._name = None self._status = None - self._api_version = None self._version = None self.discriminator = None + if api_version is not None: + self.api_version = api_version if name is not None: self.name = name if status is not None: self.status = status - if api_version is not None: - self.api_version = api_version if version is not None: self.version = version @property - def name(self): - """Gets the name of this HealthCheck. # noqa: E501 + def api_version(self): + """Gets the api_version of this InlineResponse200Data. # noqa: E501 - :return: The name of this HealthCheck. # noqa: E501 + :return: The api_version of this InlineResponse200Data. # noqa: E501 :rtype: str """ - return self._name + return self._api_version - @name.setter - def name(self, name): - """Sets the name of this HealthCheck. + @api_version.setter + def api_version(self, api_version): + """Sets the api_version of this InlineResponse200Data. - :param name: The name of this HealthCheck. # noqa: E501 + :param api_version: The api_version of this InlineResponse200Data. # noqa: E501 :type: str """ - self._name = name + self._api_version = api_version @property - def status(self): - """Gets the status of this HealthCheck. # noqa: E501 + def name(self): + """Gets the name of this InlineResponse200Data. # noqa: E501 - :return: The status of this HealthCheck. # noqa: E501 + :return: The name of this InlineResponse200Data. # noqa: E501 :rtype: str """ - return self._status + return self._name - @status.setter - def status(self, status): - """Sets the status of this HealthCheck. + @name.setter + def name(self, name): + """Sets the name of this InlineResponse200Data. - :param status: The status of this HealthCheck. # noqa: E501 + :param name: The name of this InlineResponse200Data. # noqa: E501 :type: str """ - self._status = status + self._name = name @property - def api_version(self): - """Gets the api_version of this HealthCheck. # noqa: E501 + def status(self): + """Gets the status of this InlineResponse200Data. # noqa: E501 - :return: The api_version of this HealthCheck. # noqa: E501 + :return: The status of this InlineResponse200Data. # noqa: E501 :rtype: str """ - return self._api_version + return self._status - @api_version.setter - def api_version(self, api_version): - """Sets the api_version of this HealthCheck. + @status.setter + def status(self, status): + """Sets the status of this InlineResponse200Data. - :param api_version: The api_version of this HealthCheck. # noqa: E501 + :param status: The status of this InlineResponse200Data. # noqa: E501 :type: str """ - self._api_version = api_version + self._status = status @property def version(self): - """Gets the version of this HealthCheck. # noqa: E501 + """Gets the version of this InlineResponse200Data. # noqa: E501 - :return: The version of this HealthCheck. # noqa: E501 + :return: The version of this InlineResponse200Data. # noqa: E501 :rtype: str """ return self._version @version.setter def version(self, version): - """Sets the version of this HealthCheck. + """Sets the version of this InlineResponse200Data. - :param version: The version of this HealthCheck. # noqa: E501 + :param version: The version of this InlineResponse200Data. # noqa: E501 :type: str """ @@ -181,7 +181,7 @@ def __repr__(self): def __eq__(self, other): """Returns true if both objects are equal""" - if not isinstance(other, HealthCheck): + if not isinstance(other, InlineResponse200Data): return False return self.__dict__ == other.__dict__ diff --git a/packages/director-sdk/python/simcore_director_sdk/models/health_check_enveloped.py b/packages/director-sdk/python/simcore_director_sdk/models/inline_response201.py similarity index 67% rename from packages/director-sdk/python/simcore_director_sdk/models/health_check_enveloped.py rename to packages/director-sdk/python/simcore_director_sdk/models/inline_response201.py index 673ab06b580..d92fc2b0e94 100644 --- a/packages/director-sdk/python/simcore_director_sdk/models/health_check_enveloped.py +++ b/packages/director-sdk/python/simcore_director_sdk/models/inline_response201.py @@ -17,7 +17,7 @@ import six -class HealthCheckEnveloped(object): +class InlineResponse201(object): """NOTE: This class is auto generated by OpenAPI Generator. Ref: https://openapi-generator.tech @@ -32,68 +32,68 @@ class HealthCheckEnveloped(object): and the value is json key in definition. """ openapi_types = { - 'data': 'HealthCheck', - 'status': 'int' + 'data': 'InlineResponse201Data', + 'error': 'object' } attribute_map = { 'data': 'data', - 'status': 'status' + 'error': 'error' } - def __init__(self, data=None, status=None): # noqa: E501 - """HealthCheckEnveloped - a model defined in OpenAPI""" # noqa: E501 + def __init__(self, data=None, error=None): # noqa: E501 + """InlineResponse201 - a model defined in OpenAPI""" # noqa: E501 self._data = None - self._status = None + self._error = None self.discriminator = None if data is not None: self.data = data - if status is not None: - self.status = status + if error is not None: + self.error = error @property def data(self): - """Gets the data of this HealthCheckEnveloped. # noqa: E501 + """Gets the data of this InlineResponse201. # noqa: E501 - :return: The data of this HealthCheckEnveloped. # noqa: E501 - :rtype: HealthCheck + :return: The data of this InlineResponse201. # noqa: E501 + :rtype: InlineResponse201Data """ return self._data @data.setter def data(self, data): - """Sets the data of this HealthCheckEnveloped. + """Sets the data of this InlineResponse201. - :param data: The data of this HealthCheckEnveloped. # noqa: E501 - :type: HealthCheck + :param data: The data of this InlineResponse201. # noqa: E501 + :type: InlineResponse201Data """ self._data = data @property - def status(self): - """Gets the status of this HealthCheckEnveloped. # noqa: E501 + def error(self): + """Gets the error of this InlineResponse201. # noqa: E501 - :return: The status of this HealthCheckEnveloped. # noqa: E501 - :rtype: int + :return: The error of this InlineResponse201. # noqa: E501 + :rtype: object """ - return self._status + return self._error - @status.setter - def status(self, status): - """Sets the status of this HealthCheckEnveloped. + @error.setter + def error(self, error): + """Sets the error of this InlineResponse201. - :param status: The status of this HealthCheckEnveloped. # noqa: E501 - :type: int + :param error: The error of this InlineResponse201. # noqa: E501 + :type: object """ - self._status = status + self._error = error def to_dict(self): """Returns the model properties as a dict""" @@ -129,7 +129,7 @@ def __repr__(self): def __eq__(self, other): """Returns true if both objects are equal""" - if not isinstance(other, HealthCheckEnveloped): + if not isinstance(other, InlineResponse201): return False return self.__dict__ == other.__dict__ diff --git a/packages/director-sdk/python/simcore_director_sdk/models/running_service.py b/packages/director-sdk/python/simcore_director_sdk/models/inline_response201_data.py similarity index 73% rename from packages/director-sdk/python/simcore_director_sdk/models/running_service.py rename to packages/director-sdk/python/simcore_director_sdk/models/inline_response201_data.py index 7e3b88cf9cc..a6c52275537 100644 --- a/packages/director-sdk/python/simcore_director_sdk/models/running_service.py +++ b/packages/director-sdk/python/simcore_director_sdk/models/inline_response201_data.py @@ -17,7 +17,7 @@ import six -class RunningService(object): +class InlineResponse201Data(object): """NOTE: This class is auto generated by OpenAPI Generator. Ref: https://openapi-generator.tech @@ -32,102 +32,100 @@ class RunningService(object): and the value is json key in definition. """ openapi_types = { - 'published_port': 'int', 'entry_point': 'str', + 'published_port': 'int', 'service_uuid': 'str' } attribute_map = { - 'published_port': 'published_port', 'entry_point': 'entry_point', + 'published_port': 'published_port', 'service_uuid': 'service_uuid' } - def __init__(self, published_port=None, entry_point=None, service_uuid=None): # noqa: E501 - """RunningService - a model defined in OpenAPI""" # noqa: E501 + def __init__(self, entry_point=None, published_port=None, service_uuid=None): # noqa: E501 + """InlineResponse201Data - a model defined in OpenAPI""" # noqa: E501 - self._published_port = None self._entry_point = None + self._published_port = None self._service_uuid = None self.discriminator = None - self.published_port = published_port if entry_point is not None: self.entry_point = entry_point - self.service_uuid = service_uuid + if published_port is not None: + self.published_port = published_port + if service_uuid is not None: + self.service_uuid = service_uuid + + @property + def entry_point(self): + """Gets the entry_point of this InlineResponse201Data. # noqa: E501 + + The entry point where the service provides its interface if specified # noqa: E501 + + :return: The entry_point of this InlineResponse201Data. # noqa: E501 + :rtype: str + """ + return self._entry_point + + @entry_point.setter + def entry_point(self, entry_point): + """Sets the entry_point of this InlineResponse201Data. + + The entry point where the service provides its interface if specified # noqa: E501 + + :param entry_point: The entry_point of this InlineResponse201Data. # noqa: E501 + :type: str + """ + + self._entry_point = entry_point @property def published_port(self): - """Gets the published_port of this RunningService. # noqa: E501 + """Gets the published_port of this InlineResponse201Data. # noqa: E501 The ports where the service provides its interface # noqa: E501 - :return: The published_port of this RunningService. # noqa: E501 + :return: The published_port of this InlineResponse201Data. # noqa: E501 :rtype: int """ return self._published_port @published_port.setter def published_port(self, published_port): - """Sets the published_port of this RunningService. + """Sets the published_port of this InlineResponse201Data. The ports where the service provides its interface # noqa: E501 - :param published_port: The published_port of this RunningService. # noqa: E501 + :param published_port: The published_port of this InlineResponse201Data. # noqa: E501 :type: int """ - if published_port is None: - raise ValueError("Invalid value for `published_port`, must not be `None`") # noqa: E501 if published_port is not None and published_port < 1: # noqa: E501 raise ValueError("Invalid value for `published_port`, must be a value greater than or equal to `1`") # noqa: E501 self._published_port = published_port - @property - def entry_point(self): - """Gets the entry_point of this RunningService. # noqa: E501 - - The entry point where the service provides its interface if specified # noqa: E501 - - :return: The entry_point of this RunningService. # noqa: E501 - :rtype: str - """ - return self._entry_point - - @entry_point.setter - def entry_point(self, entry_point): - """Sets the entry_point of this RunningService. - - The entry point where the service provides its interface if specified # noqa: E501 - - :param entry_point: The entry_point of this RunningService. # noqa: E501 - :type: str - """ - - self._entry_point = entry_point - @property def service_uuid(self): - """Gets the service_uuid of this RunningService. # noqa: E501 + """Gets the service_uuid of this InlineResponse201Data. # noqa: E501 The UUID attached to this service # noqa: E501 - :return: The service_uuid of this RunningService. # noqa: E501 + :return: The service_uuid of this InlineResponse201Data. # noqa: E501 :rtype: str """ return self._service_uuid @service_uuid.setter def service_uuid(self, service_uuid): - """Sets the service_uuid of this RunningService. + """Sets the service_uuid of this InlineResponse201Data. The UUID attached to this service # noqa: E501 - :param service_uuid: The service_uuid of this RunningService. # noqa: E501 + :param service_uuid: The service_uuid of this InlineResponse201Data. # noqa: E501 :type: str """ - if service_uuid is None: - raise ValueError("Invalid value for `service_uuid`, must not be `None`") # noqa: E501 self._service_uuid = service_uuid @@ -165,7 +163,7 @@ def __repr__(self): def __eq__(self, other): """Returns true if both objects are equal""" - if not isinstance(other, RunningService): + if not isinstance(other, InlineResponse201Data): return False return self.__dict__ == other.__dict__ diff --git a/packages/director-sdk/python/simcore_director_sdk/models/error_enveloped.py b/packages/director-sdk/python/simcore_director_sdk/models/inline_response204.py similarity index 68% rename from packages/director-sdk/python/simcore_director_sdk/models/error_enveloped.py rename to packages/director-sdk/python/simcore_director_sdk/models/inline_response204.py index f231a336c3c..7ddf09b671e 100644 --- a/packages/director-sdk/python/simcore_director_sdk/models/error_enveloped.py +++ b/packages/director-sdk/python/simcore_director_sdk/models/inline_response204.py @@ -17,7 +17,7 @@ import six -class ErrorEnveloped(object): +class InlineResponse204(object): """NOTE: This class is auto generated by OpenAPI Generator. Ref: https://openapi-generator.tech @@ -32,68 +32,68 @@ class ErrorEnveloped(object): and the value is json key in definition. """ openapi_types = { - 'data': 'Error', - 'status': 'int' + 'data': 'object', + 'error': 'object' } attribute_map = { 'data': 'data', - 'status': 'status' + 'error': 'error' } - def __init__(self, data=None, status=None): # noqa: E501 - """ErrorEnveloped - a model defined in OpenAPI""" # noqa: E501 + def __init__(self, data=None, error=None): # noqa: E501 + """InlineResponse204 - a model defined in OpenAPI""" # noqa: E501 self._data = None - self._status = None + self._error = None self.discriminator = None if data is not None: self.data = data - if status is not None: - self.status = status + if error is not None: + self.error = error @property def data(self): - """Gets the data of this ErrorEnveloped. # noqa: E501 + """Gets the data of this InlineResponse204. # noqa: E501 - :return: The data of this ErrorEnveloped. # noqa: E501 - :rtype: Error + :return: The data of this InlineResponse204. # noqa: E501 + :rtype: object """ return self._data @data.setter def data(self, data): - """Sets the data of this ErrorEnveloped. + """Sets the data of this InlineResponse204. - :param data: The data of this ErrorEnveloped. # noqa: E501 - :type: Error + :param data: The data of this InlineResponse204. # noqa: E501 + :type: object """ self._data = data @property - def status(self): - """Gets the status of this ErrorEnveloped. # noqa: E501 + def error(self): + """Gets the error of this InlineResponse204. # noqa: E501 - :return: The status of this ErrorEnveloped. # noqa: E501 - :rtype: int + :return: The error of this InlineResponse204. # noqa: E501 + :rtype: object """ - return self._status + return self._error - @status.setter - def status(self, status): - """Sets the status of this ErrorEnveloped. + @error.setter + def error(self, error): + """Sets the error of this InlineResponse204. - :param status: The status of this ErrorEnveloped. # noqa: E501 - :type: int + :param error: The error of this InlineResponse204. # noqa: E501 + :type: object """ - self._status = status + self._error = error def to_dict(self): """Returns the model properties as a dict""" @@ -129,7 +129,7 @@ def __repr__(self): def __eq__(self, other): """Returns true if both objects are equal""" - if not isinstance(other, ErrorEnveloped): + if not isinstance(other, InlineResponse204): return False return self.__dict__ == other.__dict__ diff --git a/packages/director-sdk/python/simcore_director_sdk/models/running_service_enveloped.py b/packages/director-sdk/python/simcore_director_sdk/models/inline_response_default.py similarity index 67% rename from packages/director-sdk/python/simcore_director_sdk/models/running_service_enveloped.py rename to packages/director-sdk/python/simcore_director_sdk/models/inline_response_default.py index edbefa1b6be..9adffde3fc3 100644 --- a/packages/director-sdk/python/simcore_director_sdk/models/running_service_enveloped.py +++ b/packages/director-sdk/python/simcore_director_sdk/models/inline_response_default.py @@ -17,7 +17,7 @@ import six -class RunningServiceEnveloped(object): +class InlineResponseDefault(object): """NOTE: This class is auto generated by OpenAPI Generator. Ref: https://openapi-generator.tech @@ -32,68 +32,68 @@ class RunningServiceEnveloped(object): and the value is json key in definition. """ openapi_types = { - 'data': 'RunningService', - 'status': 'int' + 'data': 'object', + 'error': 'InlineResponseDefaultError' } attribute_map = { 'data': 'data', - 'status': 'status' + 'error': 'error' } - def __init__(self, data=None, status=None): # noqa: E501 - """RunningServiceEnveloped - a model defined in OpenAPI""" # noqa: E501 + def __init__(self, data=None, error=None): # noqa: E501 + """InlineResponseDefault - a model defined in OpenAPI""" # noqa: E501 self._data = None - self._status = None + self._error = None self.discriminator = None if data is not None: self.data = data - if status is not None: - self.status = status + if error is not None: + self.error = error @property def data(self): - """Gets the data of this RunningServiceEnveloped. # noqa: E501 + """Gets the data of this InlineResponseDefault. # noqa: E501 - :return: The data of this RunningServiceEnveloped. # noqa: E501 - :rtype: RunningService + :return: The data of this InlineResponseDefault. # noqa: E501 + :rtype: object """ return self._data @data.setter def data(self, data): - """Sets the data of this RunningServiceEnveloped. + """Sets the data of this InlineResponseDefault. - :param data: The data of this RunningServiceEnveloped. # noqa: E501 - :type: RunningService + :param data: The data of this InlineResponseDefault. # noqa: E501 + :type: object """ self._data = data @property - def status(self): - """Gets the status of this RunningServiceEnveloped. # noqa: E501 + def error(self): + """Gets the error of this InlineResponseDefault. # noqa: E501 - :return: The status of this RunningServiceEnveloped. # noqa: E501 - :rtype: int + :return: The error of this InlineResponseDefault. # noqa: E501 + :rtype: InlineResponseDefaultError """ - return self._status + return self._error - @status.setter - def status(self, status): - """Sets the status of this RunningServiceEnveloped. + @error.setter + def error(self, error): + """Sets the error of this InlineResponseDefault. - :param status: The status of this RunningServiceEnveloped. # noqa: E501 - :type: int + :param error: The error of this InlineResponseDefault. # noqa: E501 + :type: InlineResponseDefaultError """ - self._status = status + self._error = error def to_dict(self): """Returns the model properties as a dict""" @@ -129,7 +129,7 @@ def __repr__(self): def __eq__(self, other): """Returns true if both objects are equal""" - if not isinstance(other, RunningServiceEnveloped): + if not isinstance(other, InlineResponseDefault): return False return self.__dict__ == other.__dict__ diff --git a/packages/director-sdk/python/simcore_director_sdk/models/error.py b/packages/director-sdk/python/simcore_director_sdk/models/inline_response_default_error.py similarity index 71% rename from packages/director-sdk/python/simcore_director_sdk/models/error.py rename to packages/director-sdk/python/simcore_director_sdk/models/inline_response_default_error.py index f78082a022b..92b0bdc6722 100644 --- a/packages/director-sdk/python/simcore_director_sdk/models/error.py +++ b/packages/director-sdk/python/simcore_director_sdk/models/inline_response_default_error.py @@ -17,7 +17,7 @@ import six -class Error(object): +class InlineResponseDefaultError(object): """NOTE: This class is auto generated by OpenAPI Generator. Ref: https://openapi-generator.tech @@ -32,98 +32,96 @@ class Error(object): and the value is json key in definition. """ openapi_types = { - 'message': 'str', 'errors': 'list[object]', + 'message': 'str', 'status': 'int' } attribute_map = { - 'message': 'message', 'errors': 'errors', + 'message': 'message', 'status': 'status' } - def __init__(self, message=None, errors=None, status=None): # noqa: E501 - """Error - a model defined in OpenAPI""" # noqa: E501 + def __init__(self, errors=None, message=None, status=None): # noqa: E501 + """InlineResponseDefaultError - a model defined in OpenAPI""" # noqa: E501 - self._message = None self._errors = None + self._message = None self._status = None self.discriminator = None - self.message = message if errors is not None: self.errors = errors - self.status = status + if message is not None: + self.message = message + if status is not None: + self.status = status @property - def message(self): - """Gets the message of this Error. # noqa: E501 + def errors(self): + """Gets the errors of this InlineResponseDefaultError. # noqa: E501 - Error message # noqa: E501 - :return: The message of this Error. # noqa: E501 - :rtype: str + :return: The errors of this InlineResponseDefaultError. # noqa: E501 + :rtype: list[object] """ - return self._message + return self._errors - @message.setter - def message(self, message): - """Sets the message of this Error. + @errors.setter + def errors(self, errors): + """Sets the errors of this InlineResponseDefaultError. - Error message # noqa: E501 - :param message: The message of this Error. # noqa: E501 - :type: str + :param errors: The errors of this InlineResponseDefaultError. # noqa: E501 + :type: list[object] """ - if message is None: - raise ValueError("Invalid value for `message`, must not be `None`") # noqa: E501 - self._message = message + self._errors = errors @property - def errors(self): - """Gets the errors of this Error. # noqa: E501 + def message(self): + """Gets the message of this InlineResponseDefaultError. # noqa: E501 + Error message # noqa: E501 - :return: The errors of this Error. # noqa: E501 - :rtype: list[object] + :return: The message of this InlineResponseDefaultError. # noqa: E501 + :rtype: str """ - return self._errors + return self._message - @errors.setter - def errors(self, errors): - """Sets the errors of this Error. + @message.setter + def message(self, message): + """Sets the message of this InlineResponseDefaultError. + Error message # noqa: E501 - :param errors: The errors of this Error. # noqa: E501 - :type: list[object] + :param message: The message of this InlineResponseDefaultError. # noqa: E501 + :type: str """ - self._errors = errors + self._message = message @property def status(self): - """Gets the status of this Error. # noqa: E501 + """Gets the status of this InlineResponseDefaultError. # noqa: E501 Error code # noqa: E501 - :return: The status of this Error. # noqa: E501 + :return: The status of this InlineResponseDefaultError. # noqa: E501 :rtype: int """ return self._status @status.setter def status(self, status): - """Sets the status of this Error. + """Sets the status of this InlineResponseDefaultError. Error code # noqa: E501 - :param status: The status of this Error. # noqa: E501 + :param status: The status of this InlineResponseDefaultError. # noqa: E501 :type: int """ - if status is None: - raise ValueError("Invalid value for `status`, must not be `None`") # noqa: E501 self._status = status @@ -161,7 +159,7 @@ def __repr__(self): def __eq__(self, other): """Returns true if both objects are equal""" - if not isinstance(other, Error): + if not isinstance(other, InlineResponseDefaultError): return False return self.__dict__ == other.__dict__ diff --git a/packages/director-sdk/python/simcore_director_sdk/models/node_meta_v0.py b/packages/director-sdk/python/simcore_director_sdk/models/simcore_node.py similarity index 62% rename from packages/director-sdk/python/simcore_director_sdk/models/node_meta_v0.py rename to packages/director-sdk/python/simcore_director_sdk/models/simcore_node.py index e6113b3b600..689871c4241 100644 --- a/packages/director-sdk/python/simcore_director_sdk/models/node_meta_v0.py +++ b/packages/director-sdk/python/simcore_director_sdk/models/simcore_node.py @@ -17,7 +17,7 @@ import six -class NodeMetaV0(object): +class SimcoreNode(object): """NOTE: This class is auto generated by OpenAPI Generator. Ref: https://openapi-generator.tech @@ -32,285 +32,276 @@ class NodeMetaV0(object): and the value is json key in definition. """ openapi_types = { - 'key': 'str', - 'version': 'str', - 'type': 'str', - 'name': 'str', - 'description': 'str', - 'authors': 'list[Nodemetav0Authors]', + 'authors': 'list[InlineResponse2001Authors]', 'contact': 'str', + 'description': 'str', 'inputs': 'object', - 'outputs': 'object' + 'key': 'str', + 'name': 'str', + 'outputs': 'object', + 'type': 'str', + 'version': 'str' } attribute_map = { - 'key': 'key', - 'version': 'version', - 'type': 'type', - 'name': 'name', - 'description': 'description', 'authors': 'authors', 'contact': 'contact', + 'description': 'description', 'inputs': 'inputs', - 'outputs': 'outputs' + 'key': 'key', + 'name': 'name', + 'outputs': 'outputs', + 'type': 'type', + 'version': 'version' } - def __init__(self, key=None, version=None, type=None, name=None, description=None, authors=None, contact=None, inputs=None, outputs=None): # noqa: E501 - """NodeMetaV0 - a model defined in OpenAPI""" # noqa: E501 + def __init__(self, authors=None, contact=None, description=None, inputs=None, key=None, name=None, outputs=None, type=None, version=None): # noqa: E501 + """SimcoreNode - a model defined in OpenAPI""" # noqa: E501 - self._key = None - self._version = None - self._type = None - self._name = None - self._description = None self._authors = None self._contact = None + self._description = None self._inputs = None + self._key = None + self._name = None self._outputs = None + self._type = None + self._version = None self.discriminator = None - self.key = key - self.version = version - self.type = type - self.name = name - self.description = description - self.authors = authors - self.contact = contact - self.inputs = inputs - self.outputs = outputs + if authors is not None: + self.authors = authors + if contact is not None: + self.contact = contact + if description is not None: + self.description = description + if inputs is not None: + self.inputs = inputs + if key is not None: + self.key = key + if name is not None: + self.name = name + if outputs is not None: + self.outputs = outputs + if type is not None: + self.type = type + if version is not None: + self.version = version @property - def key(self): - """Gets the key of this NodeMetaV0. # noqa: E501 + def authors(self): + """Gets the authors of this SimcoreNode. # noqa: E501 - distinctive name for the node based on the docker registry path # noqa: E501 - :return: The key of this NodeMetaV0. # noqa: E501 - :rtype: str + :return: The authors of this SimcoreNode. # noqa: E501 + :rtype: list[InlineResponse2001Authors] """ - return self._key + return self._authors - @key.setter - def key(self, key): - """Sets the key of this NodeMetaV0. + @authors.setter + def authors(self, authors): + """Sets the authors of this SimcoreNode. - distinctive name for the node based on the docker registry path # noqa: E501 - :param key: The key of this NodeMetaV0. # noqa: E501 - :type: str + :param authors: The authors of this SimcoreNode. # noqa: E501 + :type: list[InlineResponse2001Authors] """ - if key is None: - raise ValueError("Invalid value for `key`, must not be `None`") # noqa: E501 - if key is not None and not re.search('^(simcore)\/(services)\/(comp|dynamic)(\/[^\\s\/]+)+$', key): # noqa: E501 - raise ValueError("Invalid value for `key`, must be a follow pattern or equal to `/^(simcore)\/(services)\/(comp|dynamic)(\/[^\\s\/]+)+$/`") # noqa: E501 - self._key = key + self._authors = authors @property - def version(self): - """Gets the version of this NodeMetaV0. # noqa: E501 + def contact(self): + """Gets the contact of this SimcoreNode. # noqa: E501 - semantic version number # noqa: E501 + email to correspond to the authors about the node # noqa: E501 - :return: The version of this NodeMetaV0. # noqa: E501 + :return: The contact of this SimcoreNode. # noqa: E501 :rtype: str """ - return self._version + return self._contact - @version.setter - def version(self, version): - """Sets the version of this NodeMetaV0. + @contact.setter + def contact(self, contact): + """Sets the contact of this SimcoreNode. - semantic version number # noqa: E501 + email to correspond to the authors about the node # noqa: E501 - :param version: The version of this NodeMetaV0. # noqa: E501 + :param contact: The contact of this SimcoreNode. # noqa: E501 :type: str """ - if version is None: - raise ValueError("Invalid value for `version`, must not be `None`") # noqa: E501 - if version is not None and not re.search('^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$', version): # noqa: E501 - raise ValueError("Invalid value for `version`, must be a follow pattern or equal to `/^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$/`") # noqa: E501 - self._version = version + self._contact = contact @property - def type(self): - """Gets the type of this NodeMetaV0. # noqa: E501 + def description(self): + """Gets the description of this SimcoreNode. # noqa: E501 - service type # noqa: E501 + human readable description of the purpose of the node # noqa: E501 - :return: The type of this NodeMetaV0. # noqa: E501 + :return: The description of this SimcoreNode. # noqa: E501 :rtype: str """ - return self._type + return self._description - @type.setter - def type(self, type): - """Sets the type of this NodeMetaV0. + @description.setter + def description(self, description): + """Sets the description of this SimcoreNode. - service type # noqa: E501 + human readable description of the purpose of the node # noqa: E501 - :param type: The type of this NodeMetaV0. # noqa: E501 + :param description: The description of this SimcoreNode. # noqa: E501 :type: str """ - if type is None: - raise ValueError("Invalid value for `type`, must not be `None`") # noqa: E501 - allowed_values = ["computational", "dynamic"] # noqa: E501 - if type not in allowed_values: - raise ValueError( - "Invalid value for `type` ({0}), must be one of {1}" # noqa: E501 - .format(type, allowed_values) - ) - self._type = type + self._description = description @property - def name(self): - """Gets the name of this NodeMetaV0. # noqa: E501 + def inputs(self): + """Gets the inputs of this SimcoreNode. # noqa: E501 - short, human readable name for the node # noqa: E501 + definition of the inputs of this node # noqa: E501 - :return: The name of this NodeMetaV0. # noqa: E501 - :rtype: str + :return: The inputs of this SimcoreNode. # noqa: E501 + :rtype: object """ - return self._name + return self._inputs - @name.setter - def name(self, name): - """Sets the name of this NodeMetaV0. + @inputs.setter + def inputs(self, inputs): + """Sets the inputs of this SimcoreNode. - short, human readable name for the node # noqa: E501 + definition of the inputs of this node # noqa: E501 - :param name: The name of this NodeMetaV0. # noqa: E501 - :type: str + :param inputs: The inputs of this SimcoreNode. # noqa: E501 + :type: object """ - if name is None: - raise ValueError("Invalid value for `name`, must not be `None`") # noqa: E501 - self._name = name + self._inputs = inputs @property - def description(self): - """Gets the description of this NodeMetaV0. # noqa: E501 + def key(self): + """Gets the key of this SimcoreNode. # noqa: E501 - human readable description of the purpose of the node # noqa: E501 + distinctive name for the node based on the docker registry path # noqa: E501 - :return: The description of this NodeMetaV0. # noqa: E501 + :return: The key of this SimcoreNode. # noqa: E501 :rtype: str """ - return self._description + return self._key - @description.setter - def description(self, description): - """Sets the description of this NodeMetaV0. + @key.setter + def key(self, key): + """Sets the key of this SimcoreNode. - human readable description of the purpose of the node # noqa: E501 + distinctive name for the node based on the docker registry path # noqa: E501 - :param description: The description of this NodeMetaV0. # noqa: E501 + :param key: The key of this SimcoreNode. # noqa: E501 :type: str """ - if description is None: - raise ValueError("Invalid value for `description`, must not be `None`") # noqa: E501 + if key is not None and not re.search('^(simcore)\/(services)\/(comp|dynamic)(\/[^\\s\/]+)+$', key): # noqa: E501 + raise ValueError("Invalid value for `key`, must be a follow pattern or equal to `/^(simcore)\/(services)\/(comp|dynamic)(\/[^\\s\/]+)+$/`") # noqa: E501 - self._description = description + self._key = key @property - def authors(self): - """Gets the authors of this NodeMetaV0. # noqa: E501 + def name(self): + """Gets the name of this SimcoreNode. # noqa: E501 + short, human readable name for the node # noqa: E501 - :return: The authors of this NodeMetaV0. # noqa: E501 - :rtype: list[Nodemetav0Authors] + :return: The name of this SimcoreNode. # noqa: E501 + :rtype: str """ - return self._authors + return self._name - @authors.setter - def authors(self, authors): - """Sets the authors of this NodeMetaV0. + @name.setter + def name(self, name): + """Sets the name of this SimcoreNode. + short, human readable name for the node # noqa: E501 - :param authors: The authors of this NodeMetaV0. # noqa: E501 - :type: list[Nodemetav0Authors] + :param name: The name of this SimcoreNode. # noqa: E501 + :type: str """ - if authors is None: - raise ValueError("Invalid value for `authors`, must not be `None`") # noqa: E501 - self._authors = authors + self._name = name @property - def contact(self): - """Gets the contact of this NodeMetaV0. # noqa: E501 + def outputs(self): + """Gets the outputs of this SimcoreNode. # noqa: E501 - email to correspond to the authors about the node # noqa: E501 + definition of the outputs of this node # noqa: E501 - :return: The contact of this NodeMetaV0. # noqa: E501 - :rtype: str + :return: The outputs of this SimcoreNode. # noqa: E501 + :rtype: object """ - return self._contact + return self._outputs - @contact.setter - def contact(self, contact): - """Sets the contact of this NodeMetaV0. + @outputs.setter + def outputs(self, outputs): + """Sets the outputs of this SimcoreNode. - email to correspond to the authors about the node # noqa: E501 + definition of the outputs of this node # noqa: E501 - :param contact: The contact of this NodeMetaV0. # noqa: E501 - :type: str + :param outputs: The outputs of this SimcoreNode. # noqa: E501 + :type: object """ - if contact is None: - raise ValueError("Invalid value for `contact`, must not be `None`") # noqa: E501 - self._contact = contact + self._outputs = outputs @property - def inputs(self): - """Gets the inputs of this NodeMetaV0. # noqa: E501 + def type(self): + """Gets the type of this SimcoreNode. # noqa: E501 - definition of the inputs of this node # noqa: E501 + service type # noqa: E501 - :return: The inputs of this NodeMetaV0. # noqa: E501 - :rtype: object + :return: The type of this SimcoreNode. # noqa: E501 + :rtype: str """ - return self._inputs + return self._type - @inputs.setter - def inputs(self, inputs): - """Sets the inputs of this NodeMetaV0. + @type.setter + def type(self, type): + """Sets the type of this SimcoreNode. - definition of the inputs of this node # noqa: E501 + service type # noqa: E501 - :param inputs: The inputs of this NodeMetaV0. # noqa: E501 - :type: object + :param type: The type of this SimcoreNode. # noqa: E501 + :type: str """ - if inputs is None: - raise ValueError("Invalid value for `inputs`, must not be `None`") # noqa: E501 + allowed_values = ["computational", "dynamic"] # noqa: E501 + if type not in allowed_values: + raise ValueError( + "Invalid value for `type` ({0}), must be one of {1}" # noqa: E501 + .format(type, allowed_values) + ) - self._inputs = inputs + self._type = type @property - def outputs(self): - """Gets the outputs of this NodeMetaV0. # noqa: E501 + def version(self): + """Gets the version of this SimcoreNode. # noqa: E501 - definition of the outputs of this node # noqa: E501 + semantic version number # noqa: E501 - :return: The outputs of this NodeMetaV0. # noqa: E501 - :rtype: object + :return: The version of this SimcoreNode. # noqa: E501 + :rtype: str """ - return self._outputs + return self._version - @outputs.setter - def outputs(self, outputs): - """Sets the outputs of this NodeMetaV0. + @version.setter + def version(self, version): + """Sets the version of this SimcoreNode. - definition of the outputs of this node # noqa: E501 + semantic version number # noqa: E501 - :param outputs: The outputs of this NodeMetaV0. # noqa: E501 - :type: object + :param version: The version of this SimcoreNode. # noqa: E501 + :type: str """ - if outputs is None: - raise ValueError("Invalid value for `outputs`, must not be `None`") # noqa: E501 + if version is not None and not re.search('^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$', version): # noqa: E501 + raise ValueError("Invalid value for `version`, must be a follow pattern or equal to `/^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$/`") # noqa: E501 - self._outputs = outputs + self._version = version def to_dict(self): """Returns the model properties as a dict""" @@ -346,7 +337,7 @@ def __repr__(self): def __eq__(self, other): """Returns true if both objects are equal""" - if not isinstance(other, NodeMetaV0): + if not isinstance(other, SimcoreNode): return False return self.__dict__ == other.__dict__ diff --git a/packages/director-sdk/python/test/test_node_meta_v0.py b/packages/director-sdk/python/test/test_inline_response200.py similarity index 61% rename from packages/director-sdk/python/test/test_node_meta_v0.py rename to packages/director-sdk/python/test/test_inline_response200.py index 8ebe4f17e80..d37834f0e4b 100644 --- a/packages/director-sdk/python/test/test_node_meta_v0.py +++ b/packages/director-sdk/python/test/test_inline_response200.py @@ -16,12 +16,12 @@ import unittest import simcore_director_sdk -from simcore_director_sdk.models.node_meta_v0 import NodeMetaV0 # noqa: E501 +from simcore_director_sdk.models.inline_response200 import InlineResponse200 # noqa: E501 from simcore_director_sdk.rest import ApiException -class TestNodeMetaV0(unittest.TestCase): - """NodeMetaV0 unit test stubs""" +class TestInlineResponse200(unittest.TestCase): + """InlineResponse200 unit test stubs""" def setUp(self): pass @@ -29,10 +29,10 @@ def setUp(self): def tearDown(self): pass - def testNodeMetaV0(self): - """Test NodeMetaV0""" + def testInlineResponse200(self): + """Test InlineResponse200""" # FIXME: construct object with mandatory attributes with example values - # model = simcore_director_sdk.models.node_meta_v0.NodeMetaV0() # noqa: E501 + # model = simcore_director_sdk.models.inline_response200.InlineResponse200() # noqa: E501 pass diff --git a/packages/director-sdk/python/test/test_inline_response2001.py b/packages/director-sdk/python/test/test_inline_response2001.py new file mode 100644 index 00000000000..faca4a218b3 --- /dev/null +++ b/packages/director-sdk/python/test/test_inline_response2001.py @@ -0,0 +1,40 @@ +# coding: utf-8 + +""" + Director API + + This is the oSparc's director API # noqa: E501 + + OpenAPI spec version: 1.0.0 + Contact: support@simcore.com + Generated by: https://openapi-generator.tech +""" + + +from __future__ import absolute_import + +import unittest + +import simcore_director_sdk +from simcore_director_sdk.models.inline_response2001 import InlineResponse2001 # noqa: E501 +from simcore_director_sdk.rest import ApiException + + +class TestInlineResponse2001(unittest.TestCase): + """InlineResponse2001 unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def testInlineResponse2001(self): + """Test InlineResponse2001""" + # FIXME: construct object with mandatory attributes with example values + # model = simcore_director_sdk.models.inline_response2001.InlineResponse2001() # noqa: E501 + pass + + +if __name__ == '__main__': + unittest.main() diff --git a/packages/director-sdk/python/test/test_inline_response2001_authors.py b/packages/director-sdk/python/test/test_inline_response2001_authors.py new file mode 100644 index 00000000000..19df99629b0 --- /dev/null +++ b/packages/director-sdk/python/test/test_inline_response2001_authors.py @@ -0,0 +1,40 @@ +# coding: utf-8 + +""" + Director API + + This is the oSparc's director API # noqa: E501 + + OpenAPI spec version: 1.0.0 + Contact: support@simcore.com + Generated by: https://openapi-generator.tech +""" + + +from __future__ import absolute_import + +import unittest + +import simcore_director_sdk +from simcore_director_sdk.models.inline_response2001_authors import InlineResponse2001Authors # noqa: E501 +from simcore_director_sdk.rest import ApiException + + +class TestInlineResponse2001Authors(unittest.TestCase): + """InlineResponse2001Authors unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def testInlineResponse2001Authors(self): + """Test InlineResponse2001Authors""" + # FIXME: construct object with mandatory attributes with example values + # model = simcore_director_sdk.models.inline_response2001_authors.InlineResponse2001Authors() # noqa: E501 + pass + + +if __name__ == '__main__': + unittest.main() diff --git a/packages/director-sdk/python/test/test_health_check_enveloped.py b/packages/director-sdk/python/test/test_inline_response200_data.py similarity index 59% rename from packages/director-sdk/python/test/test_health_check_enveloped.py rename to packages/director-sdk/python/test/test_inline_response200_data.py index 2ae38b7580d..70fa3c9cfb5 100644 --- a/packages/director-sdk/python/test/test_health_check_enveloped.py +++ b/packages/director-sdk/python/test/test_inline_response200_data.py @@ -16,12 +16,12 @@ import unittest import simcore_director_sdk -from simcore_director_sdk.models.health_check_enveloped import HealthCheckEnveloped # noqa: E501 +from simcore_director_sdk.models.inline_response200_data import InlineResponse200Data # noqa: E501 from simcore_director_sdk.rest import ApiException -class TestHealthCheckEnveloped(unittest.TestCase): - """HealthCheckEnveloped unit test stubs""" +class TestInlineResponse200Data(unittest.TestCase): + """InlineResponse200Data unit test stubs""" def setUp(self): pass @@ -29,10 +29,10 @@ def setUp(self): def tearDown(self): pass - def testHealthCheckEnveloped(self): - """Test HealthCheckEnveloped""" + def testInlineResponse200Data(self): + """Test InlineResponse200Data""" # FIXME: construct object with mandatory attributes with example values - # model = simcore_director_sdk.models.health_check_enveloped.HealthCheckEnveloped() # noqa: E501 + # model = simcore_director_sdk.models.inline_response200_data.InlineResponse200Data() # noqa: E501 pass diff --git a/packages/director-sdk/python/test/test_error_enveloped.py b/packages/director-sdk/python/test/test_inline_response201.py similarity index 61% rename from packages/director-sdk/python/test/test_error_enveloped.py rename to packages/director-sdk/python/test/test_inline_response201.py index 415f13e5c6c..91c864c0c7e 100644 --- a/packages/director-sdk/python/test/test_error_enveloped.py +++ b/packages/director-sdk/python/test/test_inline_response201.py @@ -16,12 +16,12 @@ import unittest import simcore_director_sdk -from simcore_director_sdk.models.error_enveloped import ErrorEnveloped # noqa: E501 +from simcore_director_sdk.models.inline_response201 import InlineResponse201 # noqa: E501 from simcore_director_sdk.rest import ApiException -class TestErrorEnveloped(unittest.TestCase): - """ErrorEnveloped unit test stubs""" +class TestInlineResponse201(unittest.TestCase): + """InlineResponse201 unit test stubs""" def setUp(self): pass @@ -29,10 +29,10 @@ def setUp(self): def tearDown(self): pass - def testErrorEnveloped(self): - """Test ErrorEnveloped""" + def testInlineResponse201(self): + """Test InlineResponse201""" # FIXME: construct object with mandatory attributes with example values - # model = simcore_director_sdk.models.error_enveloped.ErrorEnveloped() # noqa: E501 + # model = simcore_director_sdk.models.inline_response201.InlineResponse201() # noqa: E501 pass diff --git a/packages/director-sdk/python/test/test_inline_response201_data.py b/packages/director-sdk/python/test/test_inline_response201_data.py new file mode 100644 index 00000000000..ae5aa893c0b --- /dev/null +++ b/packages/director-sdk/python/test/test_inline_response201_data.py @@ -0,0 +1,40 @@ +# coding: utf-8 + +""" + Director API + + This is the oSparc's director API # noqa: E501 + + OpenAPI spec version: 1.0.0 + Contact: support@simcore.com + Generated by: https://openapi-generator.tech +""" + + +from __future__ import absolute_import + +import unittest + +import simcore_director_sdk +from simcore_director_sdk.models.inline_response201_data import InlineResponse201Data # noqa: E501 +from simcore_director_sdk.rest import ApiException + + +class TestInlineResponse201Data(unittest.TestCase): + """InlineResponse201Data unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def testInlineResponse201Data(self): + """Test InlineResponse201Data""" + # FIXME: construct object with mandatory attributes with example values + # model = simcore_director_sdk.models.inline_response201_data.InlineResponse201Data() # noqa: E501 + pass + + +if __name__ == '__main__': + unittest.main() diff --git a/packages/director-sdk/python/test/test_error.py b/packages/director-sdk/python/test/test_inline_response204.py similarity index 61% rename from packages/director-sdk/python/test/test_error.py rename to packages/director-sdk/python/test/test_inline_response204.py index 6b08f8caac0..25069caf05a 100644 --- a/packages/director-sdk/python/test/test_error.py +++ b/packages/director-sdk/python/test/test_inline_response204.py @@ -16,12 +16,12 @@ import unittest import simcore_director_sdk -from simcore_director_sdk.models.error import Error # noqa: E501 +from simcore_director_sdk.models.inline_response204 import InlineResponse204 # noqa: E501 from simcore_director_sdk.rest import ApiException -class TestError(unittest.TestCase): - """Error unit test stubs""" +class TestInlineResponse204(unittest.TestCase): + """InlineResponse204 unit test stubs""" def setUp(self): pass @@ -29,10 +29,10 @@ def setUp(self): def tearDown(self): pass - def testError(self): - """Test Error""" + def testInlineResponse204(self): + """Test InlineResponse204""" # FIXME: construct object with mandatory attributes with example values - # model = simcore_director_sdk.models.error.Error() # noqa: E501 + # model = simcore_director_sdk.models.inline_response204.InlineResponse204() # noqa: E501 pass diff --git a/packages/director-sdk/python/test/test_inline_response_default.py b/packages/director-sdk/python/test/test_inline_response_default.py new file mode 100644 index 00000000000..e3d2c5f1081 --- /dev/null +++ b/packages/director-sdk/python/test/test_inline_response_default.py @@ -0,0 +1,40 @@ +# coding: utf-8 + +""" + Director API + + This is the oSparc's director API # noqa: E501 + + OpenAPI spec version: 1.0.0 + Contact: support@simcore.com + Generated by: https://openapi-generator.tech +""" + + +from __future__ import absolute_import + +import unittest + +import simcore_director_sdk +from simcore_director_sdk.models.inline_response_default import InlineResponseDefault # noqa: E501 +from simcore_director_sdk.rest import ApiException + + +class TestInlineResponseDefault(unittest.TestCase): + """InlineResponseDefault unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def testInlineResponseDefault(self): + """Test InlineResponseDefault""" + # FIXME: construct object with mandatory attributes with example values + # model = simcore_director_sdk.models.inline_response_default.InlineResponseDefault() # noqa: E501 + pass + + +if __name__ == '__main__': + unittest.main() diff --git a/packages/director-sdk/python/test/test_inline_response_default_error.py b/packages/director-sdk/python/test/test_inline_response_default_error.py new file mode 100644 index 00000000000..c28cbf8d0fe --- /dev/null +++ b/packages/director-sdk/python/test/test_inline_response_default_error.py @@ -0,0 +1,40 @@ +# coding: utf-8 + +""" + Director API + + This is the oSparc's director API # noqa: E501 + + OpenAPI spec version: 1.0.0 + Contact: support@simcore.com + Generated by: https://openapi-generator.tech +""" + + +from __future__ import absolute_import + +import unittest + +import simcore_director_sdk +from simcore_director_sdk.models.inline_response_default_error import InlineResponseDefaultError # noqa: E501 +from simcore_director_sdk.rest import ApiException + + +class TestInlineResponseDefaultError(unittest.TestCase): + """InlineResponseDefaultError unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def testInlineResponseDefaultError(self): + """Test InlineResponseDefaultError""" + # FIXME: construct object with mandatory attributes with example values + # model = simcore_director_sdk.models.inline_response_default_error.InlineResponseDefaultError() # noqa: E501 + pass + + +if __name__ == '__main__': + unittest.main() diff --git a/packages/director-sdk/python/test/test_nodemetav0_authors.py b/packages/director-sdk/python/test/test_nodemetav0_authors.py deleted file mode 100644 index 743cf54f436..00000000000 --- a/packages/director-sdk/python/test/test_nodemetav0_authors.py +++ /dev/null @@ -1,40 +0,0 @@ -# coding: utf-8 - -""" - Director API - - This is the oSparc's director API # noqa: E501 - - OpenAPI spec version: 1.0.0 - Contact: support@simcore.com - Generated by: https://openapi-generator.tech -""" - - -from __future__ import absolute_import - -import unittest - -import simcore_director_sdk -from simcore_director_sdk.models.nodemetav0_authors import Nodemetav0Authors # noqa: E501 -from simcore_director_sdk.rest import ApiException - - -class TestNodemetav0Authors(unittest.TestCase): - """Nodemetav0Authors unit test stubs""" - - def setUp(self): - pass - - def tearDown(self): - pass - - def testNodemetav0Authors(self): - """Test Nodemetav0Authors""" - # FIXME: construct object with mandatory attributes with example values - # model = simcore_director_sdk.models.nodemetav0_authors.Nodemetav0Authors() # noqa: E501 - pass - - -if __name__ == '__main__': - unittest.main() diff --git a/packages/director-sdk/python/test/test_response204_enveloped.py b/packages/director-sdk/python/test/test_response204_enveloped.py deleted file mode 100644 index f93f91b9559..00000000000 --- a/packages/director-sdk/python/test/test_response204_enveloped.py +++ /dev/null @@ -1,40 +0,0 @@ -# coding: utf-8 - -""" - Director API - - This is the oSparc's director API # noqa: E501 - - OpenAPI spec version: 1.0.0 - Contact: support@simcore.com - Generated by: https://openapi-generator.tech -""" - - -from __future__ import absolute_import - -import unittest - -import simcore_director_sdk -from simcore_director_sdk.models.response204_enveloped import Response204Enveloped # noqa: E501 -from simcore_director_sdk.rest import ApiException - - -class TestResponse204Enveloped(unittest.TestCase): - """Response204Enveloped unit test stubs""" - - def setUp(self): - pass - - def tearDown(self): - pass - - def testResponse204Enveloped(self): - """Test Response204Enveloped""" - # FIXME: construct object with mandatory attributes with example values - # model = simcore_director_sdk.models.response204_enveloped.Response204Enveloped() # noqa: E501 - pass - - -if __name__ == '__main__': - unittest.main() diff --git a/packages/director-sdk/python/test/test_running_service.py b/packages/director-sdk/python/test/test_running_service.py deleted file mode 100644 index 107807118b0..00000000000 --- a/packages/director-sdk/python/test/test_running_service.py +++ /dev/null @@ -1,40 +0,0 @@ -# coding: utf-8 - -""" - Director API - - This is the oSparc's director API # noqa: E501 - - OpenAPI spec version: 1.0.0 - Contact: support@simcore.com - Generated by: https://openapi-generator.tech -""" - - -from __future__ import absolute_import - -import unittest - -import simcore_director_sdk -from simcore_director_sdk.models.running_service import RunningService # noqa: E501 -from simcore_director_sdk.rest import ApiException - - -class TestRunningService(unittest.TestCase): - """RunningService unit test stubs""" - - def setUp(self): - pass - - def tearDown(self): - pass - - def testRunningService(self): - """Test RunningService""" - # FIXME: construct object with mandatory attributes with example values - # model = simcore_director_sdk.models.running_service.RunningService() # noqa: E501 - pass - - -if __name__ == '__main__': - unittest.main() diff --git a/packages/director-sdk/python/test/test_running_service_enveloped.py b/packages/director-sdk/python/test/test_running_service_enveloped.py deleted file mode 100644 index 10afb3aea45..00000000000 --- a/packages/director-sdk/python/test/test_running_service_enveloped.py +++ /dev/null @@ -1,40 +0,0 @@ -# coding: utf-8 - -""" - Director API - - This is the oSparc's director API # noqa: E501 - - OpenAPI spec version: 1.0.0 - Contact: support@simcore.com - Generated by: https://openapi-generator.tech -""" - - -from __future__ import absolute_import - -import unittest - -import simcore_director_sdk -from simcore_director_sdk.models.running_service_enveloped import RunningServiceEnveloped # noqa: E501 -from simcore_director_sdk.rest import ApiException - - -class TestRunningServiceEnveloped(unittest.TestCase): - """RunningServiceEnveloped unit test stubs""" - - def setUp(self): - pass - - def tearDown(self): - pass - - def testRunningServiceEnveloped(self): - """Test RunningServiceEnveloped""" - # FIXME: construct object with mandatory attributes with example values - # model = simcore_director_sdk.models.running_service_enveloped.RunningServiceEnveloped() # noqa: E501 - pass - - -if __name__ == '__main__': - unittest.main() diff --git a/packages/director-sdk/python/test/test_services_enveloped.py b/packages/director-sdk/python/test/test_services_enveloped.py deleted file mode 100644 index 628efeff228..00000000000 --- a/packages/director-sdk/python/test/test_services_enveloped.py +++ /dev/null @@ -1,40 +0,0 @@ -# coding: utf-8 - -""" - Director API - - This is the oSparc's director API # noqa: E501 - - OpenAPI spec version: 1.0.0 - Contact: support@simcore.com - Generated by: https://openapi-generator.tech -""" - - -from __future__ import absolute_import - -import unittest - -import simcore_director_sdk -from simcore_director_sdk.models.services_enveloped import ServicesEnveloped # noqa: E501 -from simcore_director_sdk.rest import ApiException - - -class TestServicesEnveloped(unittest.TestCase): - """ServicesEnveloped unit test stubs""" - - def setUp(self): - pass - - def tearDown(self): - pass - - def testServicesEnveloped(self): - """Test ServicesEnveloped""" - # FIXME: construct object with mandatory attributes with example values - # model = simcore_director_sdk.models.services_enveloped.ServicesEnveloped() # noqa: E501 - pass - - -if __name__ == '__main__': - unittest.main() diff --git a/packages/director-sdk/python/test/test_health_check.py b/packages/director-sdk/python/test/test_simcore_node.py similarity index 66% rename from packages/director-sdk/python/test/test_health_check.py rename to packages/director-sdk/python/test/test_simcore_node.py index f2039f1af72..f8e1dfd7d6f 100644 --- a/packages/director-sdk/python/test/test_health_check.py +++ b/packages/director-sdk/python/test/test_simcore_node.py @@ -16,12 +16,12 @@ import unittest import simcore_director_sdk -from simcore_director_sdk.models.health_check import HealthCheck # noqa: E501 +from simcore_director_sdk.models.simcore_node import SimcoreNode # noqa: E501 from simcore_director_sdk.rest import ApiException -class TestHealthCheck(unittest.TestCase): - """HealthCheck unit test stubs""" +class TestSimcoreNode(unittest.TestCase): + """SimcoreNode unit test stubs""" def setUp(self): pass @@ -29,10 +29,10 @@ def setUp(self): def tearDown(self): pass - def testHealthCheck(self): - """Test HealthCheck""" + def testSimcoreNode(self): + """Test SimcoreNode""" # FIXME: construct object with mandatory attributes with example values - # model = simcore_director_sdk.models.health_check.HealthCheck() # noqa: E501 + # model = simcore_director_sdk.models.simcore_node.SimcoreNode() # noqa: E501 pass diff --git a/packages/director-sdk/python/test/test_users_api.py b/packages/director-sdk/python/test/test_users_api.py index 431024fea2b..c573d86f6e5 100644 --- a/packages/director-sdk/python/test/test_users_api.py +++ b/packages/director-sdk/python/test/test_users_api.py @@ -57,6 +57,13 @@ def test_running_interactive_services_post(self): """ pass + def test_services_by_key_version_get(self): + """Test case for services_by_key_version_get + + Returns details of the selected service if available in the oSparc platform # noqa: E501 + """ + pass + def test_services_get(self): """Test case for services_get diff --git a/scripts/jsonschema/openapi_converter/converter.js b/scripts/jsonschema/openapi_converter/converter.js index e6056cc066e..66537725864 100644 --- a/scripts/jsonschema/openapi_converter/converter.js +++ b/scripts/jsonschema/openapi_converter/converter.js @@ -27,7 +27,7 @@ filenames.forEach(filepath => { // [link to problem](https://swagger.io/docs/specification/adding-examples/) yamlSchema = yamlSchema.replace(/examples:\n/g, "example:\n"); // write as yaml - fs.writeFileSync(outputPath + path.basename(filepath, ".json") + ".yaml", yamlSchema); + fs.writeFileSync(outputPath + path.basename(filepath, ".json") + "-converted.yaml", yamlSchema); // fs.writeFileSync(outputPath + "converted_" + filepath, JSON.stringify(convertedSchema)); } diff --git a/scripts/openapi/oas_resolver/Dockerfile b/scripts/openapi/oas_resolver/Dockerfile new file mode 100644 index 00000000000..92b63458149 --- /dev/null +++ b/scripts/openapi/oas_resolver/Dockerfile @@ -0,0 +1,22 @@ +# Usage: +# docker build . -t oas_resolver +# docker run -v /path/to/apis:/input -v /path/to/compiled/file:/output oas_resolver /input/path/to/openapi.yaml output_file.yaml +FROM python:3.6-alpine + +LABEL maintainer=sanderegg + +VOLUME [ "/input" ] +VOLUME [ "/output" ] + +WORKDIR /src + +# update pip +RUN pip install --no-cache-dir --upgrade \ + pip \ + wheel \ + setuptools + +RUN pip install prance && \ + pip install openapi_spec_validator + +ENTRYPOINT [ "prance", "compile" , "--backend=openapi-spec-validator"] \ No newline at end of file diff --git a/scripts/openapi/openapi_codegen.sh b/scripts/openapi/openapi_codegen.sh index 79e02448426..7ecdb99026f 100755 --- a/scripts/openapi/openapi_codegen.sh +++ b/scripts/openapi/openapi_codegen.sh @@ -28,14 +28,16 @@ usage() echo "usage: openapi_codegen [[[-i input] [-o output directory] [-g generator] [-c configuration file]] | [-h help] | [-languages] [-config-help language]]" } +openapi_generator=openapitools/openapi-generator-cli:v3.2.3 + list_languages() { - exec ${DOCKER} run --rm openapitools/openapi-generator-cli list + exec ${DOCKER} run --rm ${openapi_generator} list } print_languages_config_options() { - exec ${DOCKER} run --rm openapitools/openapi-generator-cli config-help -g $1 + exec ${DOCKER} run --rm ${openapi_generator} config-help -g $1 } ##### Main @@ -123,14 +125,14 @@ fi echo "generating code..." if [ ! -z "$configuration" ]; then - ${DOCKER} run --rm -v ${input_parent_dir}:/local -v ${output_absolute_dir}:/output -v ${configuration_parent_dir}:/config openapitools/openapi-generator-cli \ + ${DOCKER} run --rm -v ${input_parent_dir}:/local -v ${output_absolute_dir}:/output -v ${configuration_parent_dir}:/config ${openapi_generator} \ generate \ -i /local/${input_filename} \ -g ${generator} \ -o /output/${generator} \ -c /config/${configuration_filename} else - ${DOCKER} run --rm -v ${input_parent_dir}:/local -v ${output_absolute_dir}:/output openapitools/openapi-generator-cli \ + ${DOCKER} run --rm -v ${input_parent_dir}:/local -v ${output_absolute_dir}:/output ${openapi_generator} \ generate \ -i /local/${input_filename} \ -g ${generator} \ diff --git a/services/apihub/Dockerfile b/services/apihub/Dockerfile new file mode 100644 index 00000000000..5a79650fba4 --- /dev/null +++ b/services/apihub/Dockerfile @@ -0,0 +1,12 @@ +# Ultra light web server ~6MB +FROM pierrezemb/gostatic as base + +EXPOSE 8043 + +FROM base as development + +VOLUME /srv/http + +FROM base as production + +COPY apis /srv/http/apis \ No newline at end of file diff --git a/services/apihub/README.md b/services/apihub/README.md new file mode 100644 index 00000000000..879bc172764 --- /dev/null +++ b/services/apihub/README.md @@ -0,0 +1,23 @@ +# apihub + +## description + +The apihub purpose is to serve api specifications to other parts of the oSparc platform. +The file are served by default on port 8043. + +## Usage + +```bash + + # development image + docker build --target development -t apihub:dev . + docker run -v %APIS_FILES%:/srv/http/apis -p 8043:8043 apihub:dev + + # production image + docker build --target production -t apihub:prod . + docker run -p 8043:8043 apihub:prod + +``` + +It is also a part of the oSparc platform and is started together with the platform. +Note: If a service/package rely on the availability of the APIs then the apihub must be started first. \ No newline at end of file diff --git a/services/apihub/tests/conftest.py b/services/apihub/tests/conftest.py new file mode 100644 index 00000000000..803f201ad11 --- /dev/null +++ b/services/apihub/tests/conftest.py @@ -0,0 +1,40 @@ +import logging +import sys +from pathlib import Path +import requests + +import pytest + +# pylint:disable=unused-argument +log = logging.getLogger(__name__) +CURRENT_DIR = Path(sys.argv[0] if __name__ == "__main__" else __file__).parent.absolute() + + +@pytest.fixture(scope='session') +def docker_compose_file(pytestconfig): + my_path = CURRENT_DIR / "docker-compose.yml" + return my_path + +def is_responsive(url): + # api = "{url}/apis/director/v0/openapi.yaml".format(url=url) + r = requests.get(url) + if r.status_code != 200: + log.debug("Error while accessing the apihub") + return False + return True + +# pylint:disable=redefined-outer-name +@pytest.fixture(scope="session") +def apihub(docker_ip, docker_services): + host = docker_ip + port = docker_services.port_for('apihub', 8043) + url = "http://{host}:{port}".format(host=host, port=port) + # Wait until we can connect + docker_services.wait_until_responsive( + check=lambda: is_responsive(url), + timeout=30.0, + pause=1.0, + ) + + yield url + print("teardown apihub") \ No newline at end of file diff --git a/services/apihub/tests/docker-compose.yml b/services/apihub/tests/docker-compose.yml new file mode 100644 index 00000000000..8dcbc594fa0 --- /dev/null +++ b/services/apihub/tests/docker-compose.yml @@ -0,0 +1,9 @@ +version: '3' +services: + apihub: + build: + context: ../../../ + dockerfile: services/apihub/Dockerfile + # target: production + ports: + - '8043:8043' \ No newline at end of file diff --git a/services/apihub/tests/requirements.txt b/services/apihub/tests/requirements.txt new file mode 100644 index 00000000000..d0f5cd9593f --- /dev/null +++ b/services/apihub/tests/requirements.txt @@ -0,0 +1,8 @@ +coveralls~=1.3 +jsonschema~=2.6 +openapi_spec_validator +pytest~=3.6 +pytest-cov~=2.5 +pytest-docker~=0.6 +requests~=2.18 +requests-html~=0.9 \ No newline at end of file diff --git a/services/apihub/tests/test_served_apis.py b/services/apihub/tests/test_served_apis.py new file mode 100644 index 00000000000..e2dd787931d --- /dev/null +++ b/services/apihub/tests/test_served_apis.py @@ -0,0 +1,55 @@ +import io +import logging +from pathlib import Path +# from urllib.parse import urlparse + +import pytest +import yaml +from openapi_spec_validator import validate_spec +from openapi_spec_validator.exceptions import OpenAPIValidationError +from requests_html import HTMLSession + +log = logging.getLogger(__name__) + +_ROOT_DIR = Path(__file__).parent.parent.parent.parent + +def verify_links(session, links): + for link in links: + if "/tests/" in str(link): + continue + r = session.get(link) + assert r.status_code == 200 + + if "openapi.yaml" in Path(link).name: + # full api + with io.StringIO(r.text) as stream: + specs_dict = yaml.safe_load(stream) + try: + validate_spec(specs_dict, spec_url=link) + except OpenAPIValidationError as err: + pytest.fail(err.message) + + #TODO: complete this part of the test by parsing to yaml and back to string (or json) to suppress newline issues + # url_path = Path(link) + # if ".yaml" in url_path.suffix or ".json" in url_path.suffix: + # # check the same file exists and compare them + # # apis/director/v0/openapi.yaml vs http://hostname:port/apis/director/v0/openapi.yaml + # parsed_url = urlparse(link) + # corresponding_file_path = Path(str(_ROOT_DIR) + parsed_url.path) + # assert corresponding_file_path.exists() + + # with corresponding_file_path.open() as stream: + # assert r.text == stream.read() + + sublinks = r.html.absolute_links + verify_links(session, sublinks) + +def test_served_openapis_valid(apihub): + base_url = apihub + + session = HTMLSession() + r = session.get(base_url) + assert r.status_code == 200 + + links = r.html.absolute_links + verify_links(session, links) diff --git a/services/director/codegen.sh b/services/director/codegen.sh index 95624388c76..2245b968c29 100644 --- a/services/director/codegen.sh +++ b/services/director/codegen.sh @@ -4,7 +4,8 @@ # /src/package-name/.openapi/v1/package_api.yaml -- this is the input file # /src/package-name/rest/generated_code -- this is the output directory SOURCE_DIR=./src/simcore_service_director -INPUT_SPEC=${SOURCE_DIR}/oas3/v1/openapi.yaml +API_VERSION=v0 +INPUT_SPEC=${SOURCE_DIR}/oas3/${API_VERSION}/openapi.yaml OUTPUT_DIR=${SOURCE_DIR}/rest OUTPUT_DIR_GEN=${SOURCE_DIR}/rest/generated_code INIT_FILE_PATH=${OUTPUT_DIR}/__init__.py @@ -79,8 +80,6 @@ from aiohttp_apiset.swagger.operations import OperationIdMapping from .. import handlers from .models.base_model_ import Model -from .models.error import Error -from .models.error_enveloped import ErrorEnveloped log = logging.getLogger(__name__) @@ -93,16 +92,14 @@ async def __handle_errors(request, handler): except ValidationError as ex: # aiohttp apiset errors log.exception("error happened in handling route") - error = Error(status=ex.status, message=ex.to_tree()) - error_enveloped = ErrorEnveloped(data=error, status=ex.status_code) - error_dict = error_enveloped.to_dict() - return web.json_response(error_dict, status=ex.status) + error = dict(status=ex.status, message=ex.to_tree()) + error_enveloped = dict(error=error) + return web.json_response(error_enveloped, status=ex.status) except web.HTTPError as ex: log.exception("error happened in handling route") - error = Error(status=ex.status, message=str(ex.reason)) - error_enveloped = ErrorEnveloped(data=error, status=ex.status_code) - error_dict = error_enveloped.to_dict() - return web.json_response(error_dict, status=ex.status) + error = dict(status=ex.status, message=str(ex.reason)) + error_enveloped = dict(data=error) + return web.json_response(error_enveloped, status=ex.status) def create_web_app(base_folder, spec_file, additional_middlewares = None): @@ -138,8 +135,8 @@ def create_web_app(base_folder, spec_file, additional_middlewares = None): router.include( spec=Path(base_folder / spec_file), operationId_mapping=opmap, - name='v1', # name to access in swagger-ui, - basePath="/v1" # BUG: in apiset with openapi 3.0.0 [Github bug entry](https://github.com/aamalev/aiohttp_apiset/issues/45) + name='v0', # name to access in swagger-ui, + basePath="/v0" # BUG: in apiset with openapi 3.0.0 [Github bug entry](https://github.com/aamalev/aiohttp_apiset/issues/45) ) return app diff --git a/services/director/setup.py b/services/director/setup.py index 0af3c0655f1..ff403d66810 100644 --- a/services/director/setup.py +++ b/services/director/setup.py @@ -1,45 +1,77 @@ -import pathlib +import io +import re import sys +from fnmatch import fnmatch +from itertools import chain +from os import walk +from os.path import join +from pathlib import Path from setuptools import find_packages, setup -_CDIR = pathlib.Path(sys.argv[0] if __name__ == '__main__' else __file__).parent -_PACKAGES_DIR = _CDIR.absolute().parent.parent / 'packages' +_CDIR = Path(sys.argv[0] if __name__ == '__main__' else __file__).resolve().parent -def list_requirements_in(filename): - requires = [] - with (_CDIR / 'requirements' / filename).open() as fh: - requires = [line.strip() for line in fh.readlines() if not line.lstrip().startswith('#')] - return requires +if sys.version_info<(3, 6): + raise RuntimeError("Requires >=3.6, got %s. Did you forget to activate virtualenv?" % sys.version_info) -def package_files(package_dir, data_dir): - abs_path = _CDIR / package_dir / data_dir - return [str(p.relative_to(_CDIR / package_dir)) for p in abs_path.rglob('**/*.*')] +def list_datafiles_at(*locations): + def _listdir(root, wildcard='*'): + """ Recursively list all files under 'root' whose names fit a given wildcard. + Returns (dirname, files) pair per level. + See https://docs.python.org/2/distutils/setupscript.html#installing-additional-files + """ + for dirname, _, names in walk(root): + yield dirname, tuple(join(dirname, name) for name in names if fnmatch(name, wildcard)) + return list(chain.from_iterable(_listdir(root) for root in locations)) +def read(*names, **kwargs): + with io.open(join(_CDIR, *names), encoding=kwargs.get('encoding', 'utf8')) as f: + return f.read() -INSTALL_REQUIRES = list_requirements_in('base.txt') -TESTS_REQUIRE = list_requirements_in('test.txt') -PACKAGES = find_packages(where='src') -EXTRA_FILES = package_files('src/simcore_service_director', 'oas3') +def list_packages(*parts): + pkg_names = [] + COMMENT = re.compile(r'^\s*#') + with io.open(join(_CDIR, *parts)) as f: + pkg_names = [line.strip() for line in f.readlines() if not COMMENT.match(line)] + return pkg_names + ##################################################################################### +# NOTE see https://packaging.python.org/discussions/install-requires-vs-requirements/ -setup( +_CONFIG = dict( name='simcore-service-director', version='0.1.0', description='oSparc Director webserver service', - platforms=['POSIX'], - package_dir={'': 'src'}, - packages=PACKAGES, - package_data={ - '': EXTRA_FILES + author='Sylvain Anderegg (sanderegg)', + python_requires='>=3.6', + packages=find_packages(where='src'), + package_dir={ + '': 'src', }, - entry_points={ - 'console_scripts': ['simcore-service-director=simcore_service_director.__main__:main']}, include_package_data=True, - install_requires=INSTALL_REQUIRES, - tests_require=TESTS_REQUIRE, + install_requires= list_packages("requirements", "base.txt"), + tests_require=list_packages("tests", "requirements.txt"), extras_require= { - 'test': TESTS_REQUIRE + 'test': list_packages("tests", "requirements.txt") + }, + setup_requires=['pytest-runner'], + package_data={ + '': [ + 'oas3/**/*.yaml', + 'oas3/**/schemas/*.json', + 'oas3/**/schemas/*.yaml', + ], + }, + entry_points={ + 'console_scripts': [ + 'simcore-service-director = simcore_service_director.__main__:main', + ], }, - zip_safe=False, - python_requires='>=3.6', ) +def main(): + """ Execute the setup commands. + """ + setup(**_CONFIG) + return 0 # syccessful termination + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/services/director/src/simcore_service_director/config.py b/services/director/src/simcore_service_director/config.py index 82a6e0535fe..9fe199fc7b0 100644 --- a/services/director/src/simcore_service_director/config.py +++ b/services/director/src/simcore_service_director/config.py @@ -10,7 +10,7 @@ ) CONVERT_OLD_API = True -API_VERSION = "v1" +API_VERSION = "v0" REGISTRY_AUTH = os.environ.get("REGISTRY_AUTH", False) in ["true", "True"] REGISTRY_USER = os.environ.get("REGISTRY_USER", "") diff --git a/services/director/src/simcore_service_director/oas3/v0/openapi.yaml b/services/director/src/simcore_service_director/oas3/v0/openapi.yaml new file mode 100644 index 00000000000..818a85311ad --- /dev/null +++ b/services/director/src/simcore_service_director/oas3/v0/openapi.yaml @@ -0,0 +1,1494 @@ +components: + parameters: + AssignmentUuid: + description: The uuid to assign the service with + in: query + name: service_uuid + required: true + schema: + example: 123e4567-e89b-12d3-a456-426655440000 + format: uuid + type: string + ServiceKey: + description: The key (url) of the service + in: query + name: service_key + required: true + schema: + example: simcore/services/dynamic/3d-viewer + format: url + type: string + ServiceKeyPath: + description: The key (url) of the service + in: path + name: service_key + required: true + schema: + example: simcore/services/dynamic/3d-viewer + format: url + type: string + ServiceType: + description: "The service type:\n * computational - a computational service\n\ + \ * interactive - an interactive service\n" + in: query + name: service_type + required: false + schema: + enum: + - computational + - interactive + example: computational + type: string + ServiceUuid: + description: The uuid of the service + in: path + name: service_uuid + required: true + schema: + example: 123e4567-e89b-12d3-a456-426655440000 + format: uuid + type: string + ServiceVersion: + description: The tag/version of the service + in: query + name: service_tag + required: false + schema: + example: '1.4' + type: string + ServiceVersionPath: + description: The tag/version of the service + in: path + name: service_version + required: true + schema: + example: '1.4' + type: string +info: + contact: + email: support@simcore.com + name: IT'IS Foundation + description: This is the oSparc's director API + license: + name: MIT + url: https://github.com/ITISFoundation/osparc-simcore/blob/master/LICENSE + title: Director API + version: 1.0.0 +openapi: 3.0.0 +paths: + /: + get: + description: Some general information on the API and state of the service behind + operationId: root_get + responses: + '200': + content: + application/json: + schema: + properties: + data: + properties: + api_version: + example: 1.0.0-dev + type: string + name: + example: director service + type: string + status: + example: SERVICE_RUNNING + type: string + version: + example: 1dfcfdc + type: string + type: object + error: + default: null + nullable: true + type: object + required: + - data + - error + type: object + description: Service information + default: + content: + application/json: + schema: + properties: + data: + default: null + nullable: true + type: object + error: + properties: + errors: + items: + properties: + code: + description: Server Exception + example: ServiceUUIDNotFoundError + type: string + type: array + message: + description: Error message + example: Unexpected error + type: string + status: + description: Error code + example: 404 + type: integer + required: + - status + - message + type: object + required: + - data + - error + type: object + description: Unexpected error + summary: Service health-check endpoint + tags: + - users + /running_interactive_services: + post: + description: Starts an interactive service in the oSparc platform and returns + its entrypoint + operationId: running_interactive_services_post + parameters: + - description: The key (url) of the service + in: query + name: service_key + required: true + schema: + example: simcore/services/dynamic/3d-viewer + format: url + type: string + - description: The tag/version of the service + in: query + name: service_tag + required: false + schema: + example: '1.4' + type: string + - description: The uuid to assign the service with + in: query + name: service_uuid + required: true + schema: + example: 123e4567-e89b-12d3-a456-426655440000 + format: uuid + type: string + responses: + '201': + content: + application/json: + schema: + properties: + data: + properties: + entry_point: + description: The entry point where the service provides its + interface if specified + example: /the/entry/point/is/here + type: string + published_port: + description: The ports where the service provides its interface + example: 30000 + format: int32 + minimum: 1 + type: integer + service_uuid: + description: The UUID attached to this service + example: 123e4567-e89b-12d3-a456-426655440000 + format: UUID + type: string + required: + - published_port + - service_uuid + type: object + error: + default: null + nullable: true + type: object + required: + - data + - error + type: object + description: Succesfully created the service in the oSparc platform. Returns + the location where the service runs. + '400': + content: + application/json: + schema: + properties: + data: + default: null + nullable: true + type: object + error: + properties: + errors: + items: + properties: + code: + description: Server Exception + example: ServiceUUIDNotFoundError + type: string + type: array + message: + description: Error message + example: Unexpected error + type: string + status: + description: Error code + example: 404 + type: integer + required: + - status + - message + type: object + required: + - data + - error + type: object + description: Malformed function call, missing field + '401': + content: + application/json: + schema: + properties: + data: + default: null + nullable: true + type: object + error: + properties: + errors: + items: + properties: + code: + description: Server Exception + example: ServiceUUIDNotFoundError + type: string + type: array + message: + description: Error message + example: Unexpected error + type: string + status: + description: Error code + example: 404 + type: integer + required: + - status + - message + type: object + required: + - data + - error + type: object + description: Unauthorized access + '404': + content: + application/json: + schema: + properties: + data: + default: null + nullable: true + type: object + error: + properties: + errors: + items: + properties: + code: + description: Server Exception + example: ServiceUUIDNotFoundError + type: string + type: array + message: + description: Error message + example: Unexpected error + type: string + status: + description: Error code + example: 404 + type: integer + required: + - status + - message + type: object + required: + - data + - error + type: object + description: Service not found + '409': + content: + application/json: + schema: + properties: + data: + default: null + nullable: true + type: object + error: + properties: + errors: + items: + properties: + code: + description: Server Exception + example: ServiceUUIDNotFoundError + type: string + type: array + message: + description: Error message + example: Unexpected error + type: string + status: + description: Error code + example: 404 + type: integer + required: + - status + - message + type: object + required: + - data + - error + type: object + description: A service with the same uuid already exists + default: + content: + application/json: + schema: + properties: + data: + default: null + nullable: true + type: object + error: + properties: + errors: + items: + properties: + code: + description: Server Exception + example: ServiceUUIDNotFoundError + type: string + type: array + message: + description: Error message + example: Unexpected error + type: string + status: + description: Error code + example: 404 + type: integer + required: + - status + - message + type: object + required: + - data + - error + type: object + description: Unexpected error + summary: Starts an interactive service in the oSparc platform and returns its + entrypoint + tags: + - users + /running_interactive_services/{service_uuid}: + delete: + description: Stops and removes an interactive service from the oSparc platform + operationId: running_interactive_services_delete + parameters: + - description: The uuid of the service + in: path + name: service_uuid + required: true + schema: + example: 123e4567-e89b-12d3-a456-426655440000 + format: uuid + type: string + responses: + '204': + content: + application/json: + schema: + properties: + data: + default: null + nullable: true + type: object + error: + default: null + nullable: true + type: object + required: + - data + - error + type: object + description: Succesfully stopped and removed the service from the oSparc + platform + '400': + content: + application/json: + schema: + properties: + data: + default: null + nullable: true + type: object + error: + properties: + errors: + items: + properties: + code: + description: Server Exception + example: ServiceUUIDNotFoundError + type: string + type: array + message: + description: Error message + example: Unexpected error + type: string + status: + description: Error code + example: 404 + type: integer + required: + - status + - message + type: object + required: + - data + - error + type: object + description: Malformed function call, missing field + '404': + content: + application/json: + schema: + properties: + data: + default: null + nullable: true + type: object + error: + properties: + errors: + items: + properties: + code: + description: Server Exception + example: ServiceUUIDNotFoundError + type: string + type: array + message: + description: Error message + example: Unexpected error + type: string + status: + description: Error code + example: 404 + type: integer + required: + - status + - message + type: object + required: + - data + - error + type: object + description: Service not found + default: + content: + application/json: + schema: + properties: + data: + default: null + nullable: true + type: object + error: + properties: + errors: + items: + properties: + code: + description: Server Exception + example: ServiceUUIDNotFoundError + type: string + type: array + message: + description: Error message + example: Unexpected error + type: string + status: + description: Error code + example: 404 + type: integer + required: + - status + - message + type: object + required: + - data + - error + type: object + description: Unexpected error + summary: Stops and removes an interactive service from the oSparc platform + tags: + - users + get: + description: Succesfully returns if a service with the defined uuid is up and + running + operationId: running_interactive_services_get + parameters: + - description: The uuid of the service + in: path + name: service_uuid + required: true + schema: + example: 123e4567-e89b-12d3-a456-426655440000 + format: uuid + type: string + responses: + '204': + content: + application/json: + schema: + properties: + data: + default: null + nullable: true + type: object + error: + default: null + nullable: true + type: object + required: + - data + - error + type: object + description: OK service exists and runs + '400': + content: + application/json: + schema: + properties: + data: + default: null + nullable: true + type: object + error: + properties: + errors: + items: + properties: + code: + description: Server Exception + example: ServiceUUIDNotFoundError + type: string + type: array + message: + description: Error message + example: Unexpected error + type: string + status: + description: Error code + example: 404 + type: integer + required: + - status + - message + type: object + required: + - data + - error + type: object + description: Malformed function call, missing field + '404': + content: + application/json: + schema: + properties: + data: + default: null + nullable: true + type: object + error: + properties: + errors: + items: + properties: + code: + description: Server Exception + example: ServiceUUIDNotFoundError + type: string + type: array + message: + description: Error message + example: Unexpected error + type: string + status: + description: Error code + example: 404 + type: integer + required: + - status + - message + type: object + required: + - data + - error + type: object + description: Service not found + default: + content: + application/json: + schema: + properties: + data: + default: null + nullable: true + type: object + error: + properties: + errors: + items: + properties: + code: + description: Server Exception + example: ServiceUUIDNotFoundError + type: string + type: array + message: + description: Error message + example: Unexpected error + type: string + status: + description: Error code + example: 404 + type: integer + required: + - status + - message + type: object + required: + - data + - error + type: object + description: Unexpected error + summary: Succesfully returns if a service with the defined uuid is up and running + tags: + - users + /services: + get: + description: Lists available services in the oSparc platform + operationId: services_get + parameters: + - description: "The service type:\n * computational - a computational service\n\ + \ * interactive - an interactive service\n" + in: query + name: service_type + required: false + schema: + enum: + - computational + - interactive + example: computational + type: string + responses: + '200': + content: + application/json: + schema: + properties: + data: + items: + additionalProperties: false + description: Description of a simcore node 'class' with input + and output + properties: + authors: + items: + additionalProperties: false + properties: + affiliation: + description: Affiliation of the author + example: + - Sense8 + - Babylon 5 + type: string + email: + description: Email address + example: + - sun@sense.eight + - deleen@minbar.bab + format: email + type: string + name: + description: Name of the author + example: + - Sun Bak + - Delenn + type: string + required: + - name + - email + type: object + minItems: 1 + type: array + contact: + description: email to correspond to the authors about the + node + example: + - lab@net.flix + format: email + type: string + description: + description: human readable description of the purpose of + the node + example: + - Our best node type + - The mother of all nodes, makes your numbers shine! + type: string + inputs: + description: definition of the inputs of this node + type: object + x-patternProperties: + ^[-_a-zA-Z0-9]+$: + additionalProperties: false + description: all the input configurable for this service + properties: + defaultValue: + description: initial value for this input + example: + - Dog + - true + type: + - string + - number + - integer + - boolean + description: + description: description of the property + example: + - Age in seconds since 1970 + type: string + displayOrder: + description: use this to numerically sort the properties + for display + example: + - 1 + - -0.2 + type: number + fileToKeyMap: + description: Place the data associated with the + named keys in files + example: + - dir/input1.txt: key_1 + dir33/input2.txt: key2 + patternProperties: + .+: + pattern: ^[_a-z0-9]+$ + type: string + type: object + label: + description: short name for the property + example: + - Age + type: string + type: + description: data type expected on this input glob + matching for data type is allowed + example: + - number + - boolean + - data:*/* + - data:text/* + - data:[image/jpeg,image/png] + - data:application/json + - data:application/json;schema=https://my-schema/not/really/schema.json + - data:application/vnd.ms-excel + - data:text/plain + - data:application/hdf5 + - data:application/edu.ucdavis@ceclancy.xyz + pattern: ^(number|integer|boolean|string|data:([^/\s,]+/[^/\s,]+|\[[^/\s,]+/[^/\s,]+(,[^/\s]+/[^/,\s]+)*\]))$ + type: string + widget: + anyOf: + - additionalProperties: false + properties: + minHeight: + description: minimum Height of the textarea + minimum: 1 + type: integer + type: + description: type of the property + enum: + - TextArea + type: string + required: + - type + type: object + - additionalProperties: false + properties: + structure: + items: + additionalProperties: false + example: + - - key: rat + label: The Rat + - key: dog + label: Bello the Dog + properties: + key: + type: + - string + - boolean + - number + label: + type: string + required: + - key + - label + type: object + minItems: 1 + type: array + type: + description: type of the property + enum: + - SelectBox + type: string + required: + - type + - structure + type: object + description: custom widget to use instead of the + default one determined from the data-type + required: + - displayOrder + - label + - description + - type + type: object + key: + description: distinctive name for the node based on the + docker registry path + example: + - simcore/services/comp/itis/sleeper + - simcore/services/dynamic/3dviewer + pattern: ^(simcore)/(services)/(comp|dynamic)(/[^\s/]+)+$ + type: string + name: + description: short, human readable name for the node + example: + - Fast Counter + type: string + outputs: + description: definition of the outputs of this node + type: object + x-patternProperties: + ^[-_a-zA-Z0-9]+$: + additionalProperties: false + description: all the output produced by this node + properties: + description: + description: description of the property + example: + - Age in seconds since 1970 + type: string + displayOrder: + description: use this to numerically sort the properties + for display + example: + - 1 + - -0.2 + type: number + fileToKeyMap: + description: Place the data stored in the named + files and store it in the locations pointed to + by the respective output key. + example: + - dir/input1.txt: key_1 + dir33/input2.txt: key2 + patternProperties: + .+: + pattern: ^[_a-z0-9]+$ + type: string + type: object + label: + description: short name for the property + example: + - Age + type: string + type: + description: data type expected on this output + example: + - number + - integer + - boolean + - string + - data:application/json + - 'data:application/vnd.ms-excel ' + - data:text/plain + - data:application/hdf5 + pattern: ^(number|integer|boolean|string|data:[^/\s,]+/[^/\s,]+)$ + type: string + required: + - displayOrder + - label + - description + - type + type: object + type: + description: service type + enum: + - computational + - dynamic + example: + - computational + type: string + version: + description: semantic version number + example: + - 1.0.0 + - 0.0.1 + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + type: string + required: + - key + - version + - type + - name + - description + - authors + - contact + - inputs + - outputs + title: simcore node + type: object + type: array + error: + default: null + nullable: true + type: object + required: + - data + - error + type: object + description: Success, returns the list of available services + '401': + content: + application/json: + schema: + properties: + data: + default: null + nullable: true + type: object + error: + properties: + errors: + items: + properties: + code: + description: Server Exception + example: ServiceUUIDNotFoundError + type: string + type: array + message: + description: Error message + example: Unexpected error + type: string + status: + description: Error code + example: 404 + type: integer + required: + - status + - message + type: object + required: + - data + - error + type: object + description: Unauthorized access + default: + content: + application/json: + schema: + properties: + data: + default: null + nullable: true + type: object + error: + properties: + errors: + items: + properties: + code: + description: Server Exception + example: ServiceUUIDNotFoundError + type: string + type: array + message: + description: Error message + example: Unexpected error + type: string + status: + description: Error code + example: 404 + type: integer + required: + - status + - message + type: object + required: + - data + - error + type: object + description: Unexpected error + summary: Lists available services in the oSparc platform + tags: + - users + /services/{service_key}/{service_version}: + get: + description: Returns details of the selected service if available in the oSparc + platform + operationId: services_by_key_version_get + parameters: + - description: The key (url) of the service + in: path + name: service_key + required: true + schema: + example: simcore/services/dynamic/3d-viewer + format: url + type: string + - description: The tag/version of the service + in: path + name: service_version + required: true + schema: + example: '1.4' + type: string + responses: + '200': + content: + application/json: + schema: + properties: + data: + items: + additionalProperties: false + description: Description of a simcore node 'class' with input + and output + properties: + authors: + items: + additionalProperties: false + properties: + affiliation: + description: Affiliation of the author + example: + - Sense8 + - Babylon 5 + type: string + email: + description: Email address + example: + - sun@sense.eight + - deleen@minbar.bab + format: email + type: string + name: + description: Name of the author + example: + - Sun Bak + - Delenn + type: string + required: + - name + - email + type: object + minItems: 1 + type: array + contact: + description: email to correspond to the authors about the + node + example: + - lab@net.flix + format: email + type: string + description: + description: human readable description of the purpose of + the node + example: + - Our best node type + - The mother of all nodes, makes your numbers shine! + type: string + inputs: + description: definition of the inputs of this node + type: object + x-patternProperties: + ^[-_a-zA-Z0-9]+$: + additionalProperties: false + description: all the input configurable for this service + properties: + defaultValue: + description: initial value for this input + example: + - Dog + - true + type: + - string + - number + - integer + - boolean + description: + description: description of the property + example: + - Age in seconds since 1970 + type: string + displayOrder: + description: use this to numerically sort the properties + for display + example: + - 1 + - -0.2 + type: number + fileToKeyMap: + description: Place the data associated with the + named keys in files + example: + - dir/input1.txt: key_1 + dir33/input2.txt: key2 + patternProperties: + .+: + pattern: ^[_a-z0-9]+$ + type: string + type: object + label: + description: short name for the property + example: + - Age + type: string + type: + description: data type expected on this input glob + matching for data type is allowed + example: + - number + - boolean + - data:*/* + - data:text/* + - data:[image/jpeg,image/png] + - data:application/json + - data:application/json;schema=https://my-schema/not/really/schema.json + - data:application/vnd.ms-excel + - data:text/plain + - data:application/hdf5 + - data:application/edu.ucdavis@ceclancy.xyz + pattern: ^(number|integer|boolean|string|data:([^/\s,]+/[^/\s,]+|\[[^/\s,]+/[^/\s,]+(,[^/\s]+/[^/,\s]+)*\]))$ + type: string + widget: + anyOf: + - additionalProperties: false + properties: + minHeight: + description: minimum Height of the textarea + minimum: 1 + type: integer + type: + description: type of the property + enum: + - TextArea + type: string + required: + - type + type: object + - additionalProperties: false + properties: + structure: + items: + additionalProperties: false + example: + - - key: rat + label: The Rat + - key: dog + label: Bello the Dog + properties: + key: + type: + - string + - boolean + - number + label: + type: string + required: + - key + - label + type: object + minItems: 1 + type: array + type: + description: type of the property + enum: + - SelectBox + type: string + required: + - type + - structure + type: object + description: custom widget to use instead of the + default one determined from the data-type + required: + - displayOrder + - label + - description + - type + type: object + key: + description: distinctive name for the node based on the + docker registry path + example: + - simcore/services/comp/itis/sleeper + - simcore/services/dynamic/3dviewer + pattern: ^(simcore)/(services)/(comp|dynamic)(/[^\s/]+)+$ + type: string + name: + description: short, human readable name for the node + example: + - Fast Counter + type: string + outputs: + description: definition of the outputs of this node + type: object + x-patternProperties: + ^[-_a-zA-Z0-9]+$: + additionalProperties: false + description: all the output produced by this node + properties: + description: + description: description of the property + example: + - Age in seconds since 1970 + type: string + displayOrder: + description: use this to numerically sort the properties + for display + example: + - 1 + - -0.2 + type: number + fileToKeyMap: + description: Place the data stored in the named + files and store it in the locations pointed to + by the respective output key. + example: + - dir/input1.txt: key_1 + dir33/input2.txt: key2 + patternProperties: + .+: + pattern: ^[_a-z0-9]+$ + type: string + type: object + label: + description: short name for the property + example: + - Age + type: string + type: + description: data type expected on this output + example: + - number + - integer + - boolean + - string + - data:application/json + - 'data:application/vnd.ms-excel ' + - data:text/plain + - data:application/hdf5 + pattern: ^(number|integer|boolean|string|data:[^/\s,]+/[^/\s,]+)$ + type: string + required: + - displayOrder + - label + - description + - type + type: object + type: + description: service type + enum: + - computational + - dynamic + example: + - computational + type: string + version: + description: semantic version number + example: + - 1.0.0 + - 0.0.1 + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + type: string + required: + - key + - version + - type + - name + - description + - authors + - contact + - inputs + - outputs + title: simcore node + type: object + type: array + error: + default: null + nullable: true + type: object + required: + - data + - error + type: object + description: Success, returns the details of the service + '401': + content: + application/json: + schema: + properties: + data: + default: null + nullable: true + type: object + error: + properties: + errors: + items: + properties: + code: + description: Server Exception + example: ServiceUUIDNotFoundError + type: string + type: array + message: + description: Error message + example: Unexpected error + type: string + status: + description: Error code + example: 404 + type: integer + required: + - status + - message + type: object + required: + - data + - error + type: object + description: Unauthorized access + '404': + content: + application/json: + schema: + properties: + data: + default: null + nullable: true + type: object + error: + properties: + errors: + items: + properties: + code: + description: Server Exception + example: ServiceUUIDNotFoundError + type: string + type: array + message: + description: Error message + example: Unexpected error + type: string + status: + description: Error code + example: 404 + type: integer + required: + - status + - message + type: object + required: + - data + - error + type: object + description: Service not found + default: + content: + application/json: + schema: + properties: + data: + default: null + nullable: true + type: object + error: + properties: + errors: + items: + properties: + code: + description: Server Exception + example: ServiceUUIDNotFoundError + type: string + type: array + message: + description: Error message + example: Unexpected error + type: string + status: + description: Error code + example: 404 + type: integer + required: + - status + - message + type: object + required: + - data + - error + type: object + description: Unexpected error + summary: Returns details of the selected service if available in the oSparc + platform + tags: + - users +servers: +- description: Development server + url: http://{host}:{port}/{version} + variables: + host: + default: localhost + port: + default: '8001' + version: + default: v0 + enum: + - v0 +tags: +- description: Secured Admin-only calls + name: admins +- description: Operations available to regular developers + name: developers +- description: Operations available to regular users + name: users diff --git a/services/director/src/simcore_service_director/oas3/v0/schemas/node-meta-v0.0.1.json b/services/director/src/simcore_service_director/oas3/v0/schemas/node-meta-v0.0.1.json new file mode 100644 index 00000000000..2a17a13e58a --- /dev/null +++ b/services/director/src/simcore_service_director/oas3/v0/schemas/node-meta-v0.0.1.json @@ -0,0 +1,327 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + + "title": "simcore node", + "description": "Description of a simcore node 'class' with input and output", + "type": "object", + "additionalProperties": false, + "required": [ + "key", + "version", + "type", + "name", + "description", + "authors", + "contact", + "inputs", + "outputs" + ], + "properties": { + "key": { + "type": "string", + "description": "distinctive name for the node based on the docker registry path", + "pattern": "^(simcore)/(services)/(comp|dynamic)(/[^\\s/]+)+$", + "examples": [ + "simcore/services/comp/itis/sleeper", + "simcore/services/dynamic/3dviewer" + ] + }, + "version": { + "type": "string", + "description": "semantic version number", + "pattern": "^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$", + "examples": [ + "1.0.0", + "0.0.1" + ] + }, + "type": { + "type": "string", + "description": "service type", + "enum": ["computational","dynamic"], + "examples": [ + "computational" + ] + }, + "name": { + "type": "string", + "description": "short, human readable name for the node", + "examples": [ + "Fast Counter" + ] + }, + "description": { + "type": "string", + "description": "human readable description of the purpose of the node", + "examples": [ + "Our best node type", + "The mother of all nodes, makes your numbers shine!" + ] + }, + "authors": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "required": ["name", "email"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the author", + "examples": [ + "Sun Bak", + "Delenn" + ] + }, + "email": { + "description": "Email address", + "type": "string", + "format": "email", + "examples": [ + "sun@sense.eight", + "deleen@minbar.bab" + ] + }, + "affiliation": { + "description": "Affiliation of the author", + "type": "string", + "examples": [ + "Sense8", + "Babylon 5" + ] + } + } + } + }, + "contact": { + "type": "string", + "format": "email", + "description": "email to correspond to the authors about the node", + "examples": [ + "lab@net.flix" + ] + }, + "inputs": { + "type": "object", + "description": "definition of the inputs of this node", + "patternProperties": { + "^[-_a-zA-Z0-9]+$": { + "type": "object", + "description": "all the input configurable for this service", + "additionalProperties": false, + "required": [ + "displayOrder", + "label", + "description", + "type" + ], + "properties": { + "displayOrder": { + "type": "number", + "description": "use this to numerically sort the properties for display", + "examples": [ + 1, + -0.2 + ] + }, + "label": { + "type": "string", + "description": "short name for the property", + "examples": [ + "Age" + ] + }, + "description": { + "type": "string", + "description": "description of the property", + "examples": [ + "Age in seconds since 1970" + ] + }, + "type": { + "type": "string", + "pattern": "^(number|integer|boolean|string|data:([^/\\s,]+/[^/\\s,]+|\\[[^/\\s,]+/[^/\\s,]+(,[^/\\s]+/[^/,\\s]+)*\\]))$", + "description": "data type expected on this input glob matching for data type is allowed", + "examples": [ + "number", + "boolean", + "data:*/*", + "data:text/*", + "data:[image/jpeg,image/png]", + "data:application/json", + "data:application/json;schema=https://my-schema/not/really/schema.json", + "data:application/vnd.ms-excel", + "data:text/plain", + "data:application/hdf5", + "data:application/edu.ucdavis@ceclancy.xyz" + ] + }, + "fileToKeyMap": { + "description": "Place the data associated with the named keys in files", + + "type": "object", + "patternProperties": { + ".+": { + "type": "string", + "pattern": "^[_a-z0-9]+$" + } + }, + "examples": [ + { + "dir/input1.txt": "key_1", + "dir33/input2.txt": "key2" + } + ] + }, + "defaultValue": { + "description": "initial value for this input", + "type": ["string","number","integer","boolean"], + "examples": [ + "Dog", + true + ] + }, + "widget": { + "description": "custom widget to use instead of the default one determined from the data-type", + "anyOf": [ + { + "type": "object", + "additionalProperties": false, + "required": [ + "type" + ], + "properties": { + "type": { + "description": "type of the property", + "type": "string", + "enum": ["TextArea"] + }, + "minHeight": { + "description": "minimum Height of the textarea", + "type": "integer", + "minimum": 1 + } + } + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "structure" + ], + "properties": { + "type": { + "description": "type of the property", + "type": "string", + "enum": ["SelectBox"] + }, + "structure": { + "type": "array", + "minItems": 1, + "items": { + "type":"object", + "additionalProperties": false, + "required": [ + "key", + "label" + ], + "properties": { + "key": { + "type": ["string","boolean","number"] + }, + "label": { + "type": "string" + } + }, + "examples": [ + [ + { "key": "rat", "label": "The Rat"}, + { "key": "dog", "label": "Bello the Dog"} + ] + ] + } + } + } + } + ] + } + } + } + } + }, + "outputs": { + "type": "object", + "description": "definition of the outputs of this node", + "patternProperties": { + "^[-_a-zA-Z0-9]+$": { + "type": "object", + "description": "all the output produced by this node", + "additionalProperties": false, + "required": [ + "displayOrder", + "label", + "description", + "type" + ], + "properties": { + "displayOrder": { + "type": "number", + "description": "use this to numerically sort the properties for display", + "examples": [ + 1, + -0.2 + ] + }, + "label": { + "type": "string", + "description": "short name for the property", + "examples": [ + "Age" + ] + }, + "description": { + "type": "string", + "description": "description of the property", + "examples": [ + "Age in seconds since 1970" + ] + }, + "type": { + "type": "string", + "pattern": "^(number|integer|boolean|string|data:[^/\\s,]+/[^/\\s,]+)$", + "description": "data type expected on this output", + "examples": [ + "number", + "integer", + "boolean", + "string", + "data:application/json", + "data:application/vnd.ms-excel ", + "data:text/plain", + "data:application/hdf5" + ] + }, + "fileToKeyMap": { + "description": "Place the data stored in the named files and store it in the locations pointed to by the respective output key.", + "type": "object", + "patternProperties": { + ".+": { + "type": "string", + "pattern": "^[_a-z0-9]+$" + } + }, + "examples": [ + { + "dir/input1.txt": "key_1", + "dir33/input2.txt": "key2" + } + ] + } + } + } + } + } + } +} diff --git a/services/director/src/simcore_service_director/oas3/v1/components/parameters/assignment_uuid.yaml b/services/director/src/simcore_service_director/oas3/v1/components/parameters/assignment_uuid.yaml deleted file mode 100644 index c5aa54a56b5..00000000000 --- a/services/director/src/simcore_service_director/oas3/v1/components/parameters/assignment_uuid.yaml +++ /dev/null @@ -1,9 +0,0 @@ -AssignmentUuid: - in: query - name: service_uuid - description: The uuid to assign the service with - required: true - schema: - type: string - format: uuid - example: 123e4567-e89b-12d3-a456-426655440000 \ No newline at end of file diff --git a/services/director/src/simcore_service_director/oas3/v1/components/parameters/service_key.yaml b/services/director/src/simcore_service_director/oas3/v1/components/parameters/service_key.yaml deleted file mode 100644 index 730668c69f7..00000000000 --- a/services/director/src/simcore_service_director/oas3/v1/components/parameters/service_key.yaml +++ /dev/null @@ -1,9 +0,0 @@ -ServiceKey: - in: query - name: service_key - description: The key (url) of the service - required: true - schema: - type: string - format: url - example: simcore/services/dynamic/3d-viewer \ No newline at end of file diff --git a/services/director/src/simcore_service_director/oas3/v1/components/parameters/service_key_path.yaml b/services/director/src/simcore_service_director/oas3/v1/components/parameters/service_key_path.yaml deleted file mode 100644 index 3efe70f6db2..00000000000 --- a/services/director/src/simcore_service_director/oas3/v1/components/parameters/service_key_path.yaml +++ /dev/null @@ -1,9 +0,0 @@ -ServiceKeyPath: - in: path - name: service_key - description: The key (url) of the service - required: true - schema: - type: string - format: url - example: simcore/services/dynamic/3d-viewer \ No newline at end of file diff --git a/services/director/src/simcore_service_director/oas3/v1/components/parameters/service_type.yaml b/services/director/src/simcore_service_director/oas3/v1/components/parameters/service_type.yaml deleted file mode 100644 index 768225c9205..00000000000 --- a/services/director/src/simcore_service_director/oas3/v1/components/parameters/service_type.yaml +++ /dev/null @@ -1,14 +0,0 @@ -ServiceType: - in: query - name: service_type - description: | - The service type: - * computational - a computational service - * interactive - an interactive service - required: false - schema: - type: string - enum: - - computational - - interactive - example: computational \ No newline at end of file diff --git a/services/director/src/simcore_service_director/oas3/v1/components/parameters/service_uuid.yaml b/services/director/src/simcore_service_director/oas3/v1/components/parameters/service_uuid.yaml deleted file mode 100644 index 938ffa72826..00000000000 --- a/services/director/src/simcore_service_director/oas3/v1/components/parameters/service_uuid.yaml +++ /dev/null @@ -1,9 +0,0 @@ -ServiceUuid: - in: path - name: service_uuid - description: The uuid of the service - required: true - schema: - type: string - format: uuid - example: 123e4567-e89b-12d3-a456-426655440000 \ No newline at end of file diff --git a/services/director/src/simcore_service_director/oas3/v1/components/parameters/service_version.yaml b/services/director/src/simcore_service_director/oas3/v1/components/parameters/service_version.yaml deleted file mode 100644 index f7b5648eb0c..00000000000 --- a/services/director/src/simcore_service_director/oas3/v1/components/parameters/service_version.yaml +++ /dev/null @@ -1,8 +0,0 @@ -ServiceVersion: - in: query - name: service_tag - description: The tag/version of the service - required: false - schema: - type: string - example: "1.4" \ No newline at end of file diff --git a/services/director/src/simcore_service_director/oas3/v1/components/parameters/service_version_path.yaml b/services/director/src/simcore_service_director/oas3/v1/components/parameters/service_version_path.yaml deleted file mode 100644 index 96f2980bb9b..00000000000 --- a/services/director/src/simcore_service_director/oas3/v1/components/parameters/service_version_path.yaml +++ /dev/null @@ -1,8 +0,0 @@ -ServiceVersionPath: - in: path - name: service_version - description: The tag/version of the service - required: true - schema: - type: string - example: "1.4" \ No newline at end of file diff --git a/services/director/src/simcore_service_director/oas3/v1/components/schemas/response204.yaml b/services/director/src/simcore_service_director/oas3/v1/components/schemas/response204.yaml deleted file mode 100644 index e9c9506231b..00000000000 --- a/services/director/src/simcore_service_director/oas3/v1/components/schemas/response204.yaml +++ /dev/null @@ -1,12 +0,0 @@ -Response204Enveloped: - type: object - properties: - data: - type: string - nullable: true - example: 'null' - default: 'null' - status: - type: integer - example: 204 - default: 204 \ No newline at end of file diff --git a/services/director/src/simcore_service_director/oas3/v1/components/schemas/services.yaml b/services/director/src/simcore_service_director/oas3/v1/components/schemas/services.yaml deleted file mode 100644 index 93eb0243927..00000000000 --- a/services/director/src/simcore_service_director/oas3/v1/components/schemas/services.yaml +++ /dev/null @@ -1,10 +0,0 @@ -ServicesEnveloped: - type: object - properties: - data: - type: array - items: - $ref: './node-meta-v0.0.1.yaml' - status: - type: integer - example: 200 \ No newline at end of file diff --git a/services/director/src/simcore_service_director/oas3/v1/openapi.yaml b/services/director/src/simcore_service_director/oas3/v1/openapi.yaml deleted file mode 100644 index 4311da1832f..00000000000 --- a/services/director/src/simcore_service_director/oas3/v1/openapi.yaml +++ /dev/null @@ -1,50 +0,0 @@ -openapi: "3.0.0" -info: - description: This is the oSparc's director API - version: 1.0.0 - title: Director API - # put the contact info for your development or API team - contact: - name: IT'IS Foundation - email: support@simcore.com - license: - name: MIT - url: https://github.com/ITISFoundation/osparc-simcore/blob/master/LICENSE - -servers: - - url: http://{host}:{port}/{version} - description: Development server - variables: - host: - default: 'localhost' - port: - default: '8001' - version: - default: 'v1' - enum: - - 'v1' - -# tags are used for organizing operations -tags: -- name: admins - description: Secured Admin-only calls -- name: developers - description: Operations available to regular developers -- name: users - description: Operations available to regular users - -paths: - /: - $ref: './paths/health_check.yaml' - - /services: - $ref: './paths/services.yaml' - - /services/{service_key}/{service_version}: - $ref: './paths/services-by-key-and-version.yaml' - - /running_interactive_services: - $ref: './paths/running_interactive_services.yaml' - - /running_interactive_services/{service_uuid}: - $ref: './paths/running_interactive_services-by-uuid.yaml' diff --git a/services/director/src/simcore_service_director/oas3/v1/paths/health_check.yaml b/services/director/src/simcore_service_director/oas3/v1/paths/health_check.yaml deleted file mode 100644 index d0487d0292d..00000000000 --- a/services/director/src/simcore_service_director/oas3/v1/paths/health_check.yaml +++ /dev/null @@ -1,19 +0,0 @@ -get: - tags: - - users - summary: Service health-check endpoint - description: Some general information on the API and state of the service behind - operationId: root_get - responses: - "200": - description: Service information - content: - application/json: - schema: - $ref: '../components/schemas/health_check.yaml#HealthCheckEnveloped' - default: - description: Unexpected error - content: - application/json: - schema: - $ref: '../components/schemas/error.yaml#ErrorEnveloped' \ No newline at end of file diff --git a/services/director/src/simcore_service_director/oas3/v1/paths/running_interactive_services-by-uuid.yaml b/services/director/src/simcore_service_director/oas3/v1/paths/running_interactive_services-by-uuid.yaml deleted file mode 100644 index 73cd09f97ea..00000000000 --- a/services/director/src/simcore_service_director/oas3/v1/paths/running_interactive_services-by-uuid.yaml +++ /dev/null @@ -1,66 +0,0 @@ -get: - tags: - - users - summary: Succesfully returns if a service with the defined uuid is up and running - description: Succesfully returns if a service with the defined uuid is up and running - operationId: running_interactive_services_get - parameters: - - $ref: '../components/parameters/service_uuid.yaml#ServiceUuid' - responses: - "204": - description: OK service exists and runs - content: - application/json: - schema: - $ref: '../components/schemas/response204.yaml#Response204Enveloped' - "400": - description: Malformed function call, missing field - content: - application/json: - schema: - $ref: '../components/schemas/error.yaml#ErrorEnveloped' - "404": - description: Service not found - content: - application/json: - schema: - $ref: '../components/schemas/error.yaml#ErrorEnveloped' - default: - description: Unexpected error - content: - application/json: - schema: - $ref: '../components/schemas/error.yaml#ErrorEnveloped' -delete: - tags: - - users - summary: Stops and removes an interactive service from the oSparc platform - description: Stops and removes an interactive service from the oSparc platform - operationId: running_interactive_services_delete - parameters: - - $ref: '../components/parameters/service_uuid.yaml#ServiceUuid' - responses: - "204": - description: Succesfully stopped and removed the service from the oSparc platform - content: - application/json: - schema: - $ref: '../components/schemas/response204.yaml#Response204Enveloped' - "400": - description: Malformed function call, missing field - content: - application/json: - schema: - $ref: '../components/schemas/error.yaml#ErrorEnveloped' - "404": - description: Service not found - content: - application/json: - schema: - $ref: '../components/schemas/error.yaml#ErrorEnveloped' - default: - description: Unexpected error - content: - application/json: - schema: - $ref: '../components/schemas/error.yaml#ErrorEnveloped' \ No newline at end of file diff --git a/services/director/src/simcore_service_director/oas3/v1/paths/running_interactive_services.yaml b/services/director/src/simcore_service_director/oas3/v1/paths/running_interactive_services.yaml deleted file mode 100644 index 050eb0715aa..00000000000 --- a/services/director/src/simcore_service_director/oas3/v1/paths/running_interactive_services.yaml +++ /dev/null @@ -1,47 +0,0 @@ -post: - tags: - - users - summary: Starts an interactive service in the oSparc platform and returns its entrypoint - description: Starts an interactive service in the oSparc platform and returns its entrypoint - operationId: running_interactive_services_post - parameters: - - $ref: '../components/parameters/service_key.yaml#ServiceKey' - - $ref: '../components/parameters/service_version.yaml#ServiceVersion' - - $ref: '../components/parameters/assignment_uuid.yaml#AssignmentUuid' - responses: - "201": - description: Succesfully created the service in the oSparc platform. Returns the location where the service runs. - content: - application/json: - schema: - $ref: '../components/schemas/running_service.yaml#RunningServiceEnveloped' - "400": - description: Malformed function call, missing field - content: - application/json: - schema: - $ref: '../components/schemas/error.yaml#ErrorEnveloped' - "401": - description: Unauthorized access - content: - application/json: - schema: - $ref: '../components/schemas/error.yaml#ErrorEnveloped' - "404": - description: Service not found - content: - application/json: - schema: - $ref: '../components/schemas/error.yaml#ErrorEnveloped' - "409": - description: A service with the same uuid already exists - content: - application/json: - schema: - $ref: '../components/schemas/error.yaml#ErrorEnveloped' - default: - description: Unexpected error - content: - application/json: - schema: - $ref: '../components/schemas/error.yaml#ErrorEnveloped' \ No newline at end of file diff --git a/services/director/src/simcore_service_director/oas3/v1/paths/services-by-key-and-version.yaml b/services/director/src/simcore_service_director/oas3/v1/paths/services-by-key-and-version.yaml deleted file mode 100644 index d8ca0f92706..00000000000 --- a/services/director/src/simcore_service_director/oas3/v1/paths/services-by-key-and-version.yaml +++ /dev/null @@ -1,34 +0,0 @@ -get: - tags: - - users - summary: Returns details of the selected service if available in the oSparc platform - description: Returns details of the selected service if available in the oSparc platform - operationId: services_by_key_version_get - parameters: - - $ref: '../components/parameters/service_key_path.yaml#ServiceKeyPath' - - $ref: '../components/parameters/service_version_path.yaml#ServiceVersionPath' - responses: - "200": - description: Success, returns the details of the service - content: - application/json: - schema: - $ref: '../components/schemas/services.yaml#ServicesEnveloped' - "401": - description: Unauthorized access - content: - application/json: - schema: - $ref: '../components/schemas/error.yaml#ErrorEnveloped' - "404": - description: Service not found - content: - application/json: - schema: - $ref: '../components/schemas/error.yaml#ErrorEnveloped' - default: - description: Unexpected error - content: - application/json: - schema: - $ref: '../components/schemas/error.yaml#ErrorEnveloped' \ No newline at end of file diff --git a/services/director/src/simcore_service_director/oas3/v1/paths/services.yaml b/services/director/src/simcore_service_director/oas3/v1/paths/services.yaml deleted file mode 100644 index 11d9c817cfa..00000000000 --- a/services/director/src/simcore_service_director/oas3/v1/paths/services.yaml +++ /dev/null @@ -1,27 +0,0 @@ -get: - tags: - - users - summary: Lists available services in the oSparc platform - description: Lists available services in the oSparc platform - operationId: services_get - parameters: - - $ref: '../components/parameters/service_type.yaml#ServiceType' - responses: - "200": - description: Success, returns the list of available services - content: - application/json: - schema: - $ref: '../components/schemas/services.yaml#ServicesEnveloped' - "401": - description: Unauthorized access - content: - application/json: - schema: - $ref: '../components/schemas/error.yaml#ErrorEnveloped' - default: - description: Unexpected error - content: - application/json: - schema: - $ref: '../components/schemas/error.yaml#ErrorEnveloped' \ No newline at end of file diff --git a/services/director/src/simcore_service_director/resources.py b/services/director/src/simcore_service_director/resources.py index 19407f78aac..c477ef581df 100644 --- a/services/director/src/simcore_service_director/resources.py +++ b/services/director/src/simcore_service_director/resources.py @@ -6,7 +6,7 @@ RESOURCE_OPENAPI_ROOT = "oas3" RESOURCE_OPEN_API = "{root}/{version}/openapi.yaml".format(root=RESOURCE_OPENAPI_ROOT, version=config.API_VERSION) -RESOURCE_NODE_SCHEMA = "{root}/{version}/components/schemas/node-meta-v0.0.1.json".format(root=RESOURCE_OPENAPI_ROOT, version=config.API_VERSION) +RESOURCE_NODE_SCHEMA = "{root}/{version}/schemas/node-meta-v0.0.1.json".format(root=RESOURCE_OPENAPI_ROOT, version=config.API_VERSION) """ List of pkg_resources functions *bound* to current package with the following signature diff --git a/services/director/src/simcore_service_director/rest/generated_code/models/__init__.py b/services/director/src/simcore_service_director/rest/generated_code/models/__init__.py index 698c1650c1d..ec9e20efd87 100644 --- a/services/director/src/simcore_service_director/rest/generated_code/models/__init__.py +++ b/services/director/src/simcore_service_director/rest/generated_code/models/__init__.py @@ -3,13 +3,13 @@ # flake8: noqa from __future__ import absolute_import # import models into model package -from .error import Error -from .error_enveloped import ErrorEnveloped -from .health_check import HealthCheck -from .health_check_enveloped import HealthCheckEnveloped -from .node_meta_v0 import NodeMetaV0 -from .nodemetav0_authors import Nodemetav0Authors -from .response204_enveloped import Response204Enveloped -from .running_service import RunningService -from .running_service_enveloped import RunningServiceEnveloped -from .services_enveloped import ServicesEnveloped +from .inline_response200 import InlineResponse200 +from .inline_response2001 import InlineResponse2001 +from .inline_response2001_authors import InlineResponse2001Authors +from .inline_response200_data import InlineResponse200Data +from .inline_response201 import InlineResponse201 +from .inline_response201_data import InlineResponse201Data +from .inline_response204 import InlineResponse204 +from .inline_response_default import InlineResponseDefault +from .inline_response_default_error import InlineResponseDefaultError +from .simcore_node import SimcoreNode diff --git a/services/director/src/simcore_service_director/rest/generated_code/models/error_enveloped.py b/services/director/src/simcore_service_director/rest/generated_code/models/error_enveloped.py deleted file mode 100644 index 502c78337ad..00000000000 --- a/services/director/src/simcore_service_director/rest/generated_code/models/error_enveloped.py +++ /dev/null @@ -1,91 +0,0 @@ -# coding: utf-8 - -from __future__ import absolute_import -from datetime import date, datetime # noqa: F401 - -from typing import List, Dict # noqa: F401 - -from .base_model_ import Model -from .error import Error # noqa: F401,E501 -from .. import util - - -class ErrorEnveloped(Model): - """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - - Do not edit the class manually. - """ - - def __init__(self, data: Error=None, status: int=None): # noqa: E501 - """ErrorEnveloped - a model defined in OpenAPI - - :param data: The data of this ErrorEnveloped. # noqa: E501 - :type data: Error - :param status: The status of this ErrorEnveloped. # noqa: E501 - :type status: int - """ - self.openapi_types = { - 'data': Error, - 'status': int - } - - self.attribute_map = { - 'data': 'data', - 'status': 'status' - } - - self._data = data - self._status = status - - @classmethod - def from_dict(cls, dikt) -> 'ErrorEnveloped': - """Returns the dict as a model - - :param dikt: A dict. - :type: dict - :return: The ErrorEnveloped of this ErrorEnveloped. # noqa: E501 - :rtype: ErrorEnveloped - """ - return util.deserialize_model(dikt, cls) - - @property - def data(self) -> Error: - """Gets the data of this ErrorEnveloped. - - - :return: The data of this ErrorEnveloped. - :rtype: Error - """ - return self._data - - @data.setter - def data(self, data: Error): - """Sets the data of this ErrorEnveloped. - - - :param data: The data of this ErrorEnveloped. - :type data: Error - """ - - self._data = data - - @property - def status(self) -> int: - """Gets the status of this ErrorEnveloped. - - - :return: The status of this ErrorEnveloped. - :rtype: int - """ - return self._status - - @status.setter - def status(self, status: int): - """Sets the status of this ErrorEnveloped. - - - :param status: The status of this ErrorEnveloped. - :type status: int - """ - - self._status = status diff --git a/services/director/src/simcore_service_director/rest/generated_code/models/health_check_enveloped.py b/services/director/src/simcore_service_director/rest/generated_code/models/health_check_enveloped.py deleted file mode 100644 index d24b343c4f3..00000000000 --- a/services/director/src/simcore_service_director/rest/generated_code/models/health_check_enveloped.py +++ /dev/null @@ -1,91 +0,0 @@ -# coding: utf-8 - -from __future__ import absolute_import -from datetime import date, datetime # noqa: F401 - -from typing import List, Dict # noqa: F401 - -from .base_model_ import Model -from .health_check import HealthCheck # noqa: F401,E501 -from .. import util - - -class HealthCheckEnveloped(Model): - """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - - Do not edit the class manually. - """ - - def __init__(self, data: HealthCheck=None, status: int=None): # noqa: E501 - """HealthCheckEnveloped - a model defined in OpenAPI - - :param data: The data of this HealthCheckEnveloped. # noqa: E501 - :type data: HealthCheck - :param status: The status of this HealthCheckEnveloped. # noqa: E501 - :type status: int - """ - self.openapi_types = { - 'data': HealthCheck, - 'status': int - } - - self.attribute_map = { - 'data': 'data', - 'status': 'status' - } - - self._data = data - self._status = status - - @classmethod - def from_dict(cls, dikt) -> 'HealthCheckEnveloped': - """Returns the dict as a model - - :param dikt: A dict. - :type: dict - :return: The HealthCheckEnveloped of this HealthCheckEnveloped. # noqa: E501 - :rtype: HealthCheckEnveloped - """ - return util.deserialize_model(dikt, cls) - - @property - def data(self) -> HealthCheck: - """Gets the data of this HealthCheckEnveloped. - - - :return: The data of this HealthCheckEnveloped. - :rtype: HealthCheck - """ - return self._data - - @data.setter - def data(self, data: HealthCheck): - """Sets the data of this HealthCheckEnveloped. - - - :param data: The data of this HealthCheckEnveloped. - :type data: HealthCheck - """ - - self._data = data - - @property - def status(self) -> int: - """Gets the status of this HealthCheckEnveloped. - - - :return: The status of this HealthCheckEnveloped. - :rtype: int - """ - return self._status - - @status.setter - def status(self, status: int): - """Sets the status of this HealthCheckEnveloped. - - - :param status: The status of this HealthCheckEnveloped. - :type status: int - """ - - self._status = status diff --git a/services/director/src/simcore_service_director/rest/generated_code/models/inline_response200.py b/services/director/src/simcore_service_director/rest/generated_code/models/inline_response200.py new file mode 100644 index 00000000000..d0f3398e545 --- /dev/null +++ b/services/director/src/simcore_service_director/rest/generated_code/models/inline_response200.py @@ -0,0 +1,91 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from .base_model_ import Model +from .inline_response200_data import InlineResponse200Data # noqa: F401,E501 +from .. import util + + +class InlineResponse200(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, data: InlineResponse200Data=None, error: object=None): # noqa: E501 + """InlineResponse200 - a model defined in OpenAPI + + :param data: The data of this InlineResponse200. # noqa: E501 + :type data: InlineResponse200Data + :param error: The error of this InlineResponse200. # noqa: E501 + :type error: object + """ + self.openapi_types = { + 'data': InlineResponse200Data, + 'error': object + } + + self.attribute_map = { + 'data': 'data', + 'error': 'error' + } + + self._data = data + self._error = error + + @classmethod + def from_dict(cls, dikt) -> 'InlineResponse200': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The inline_response_200 of this InlineResponse200. # noqa: E501 + :rtype: InlineResponse200 + """ + return util.deserialize_model(dikt, cls) + + @property + def data(self) -> InlineResponse200Data: + """Gets the data of this InlineResponse200. + + + :return: The data of this InlineResponse200. + :rtype: InlineResponse200Data + """ + return self._data + + @data.setter + def data(self, data: InlineResponse200Data): + """Sets the data of this InlineResponse200. + + + :param data: The data of this InlineResponse200. + :type data: InlineResponse200Data + """ + + self._data = data + + @property + def error(self) -> object: + """Gets the error of this InlineResponse200. + + + :return: The error of this InlineResponse200. + :rtype: object + """ + return self._error + + @error.setter + def error(self, error: object): + """Sets the error of this InlineResponse200. + + + :param error: The error of this InlineResponse200. + :type error: object + """ + + self._error = error diff --git a/services/director/src/simcore_service_director/rest/generated_code/models/inline_response2001.py b/services/director/src/simcore_service_director/rest/generated_code/models/inline_response2001.py new file mode 100644 index 00000000000..9c363d131b6 --- /dev/null +++ b/services/director/src/simcore_service_director/rest/generated_code/models/inline_response2001.py @@ -0,0 +1,91 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from .base_model_ import Model +from .simcore_node import SimcoreNode # noqa: F401,E501 +from .. import util + + +class InlineResponse2001(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, data: List[SimcoreNode]=None, error: object=None): # noqa: E501 + """InlineResponse2001 - a model defined in OpenAPI + + :param data: The data of this InlineResponse2001. # noqa: E501 + :type data: List[SimcoreNode] + :param error: The error of this InlineResponse2001. # noqa: E501 + :type error: object + """ + self.openapi_types = { + 'data': List[SimcoreNode], + 'error': object + } + + self.attribute_map = { + 'data': 'data', + 'error': 'error' + } + + self._data = data + self._error = error + + @classmethod + def from_dict(cls, dikt) -> 'InlineResponse2001': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The inline_response_200_1 of this InlineResponse2001. # noqa: E501 + :rtype: InlineResponse2001 + """ + return util.deserialize_model(dikt, cls) + + @property + def data(self) -> List[SimcoreNode]: + """Gets the data of this InlineResponse2001. + + + :return: The data of this InlineResponse2001. + :rtype: List[SimcoreNode] + """ + return self._data + + @data.setter + def data(self, data: List[SimcoreNode]): + """Sets the data of this InlineResponse2001. + + + :param data: The data of this InlineResponse2001. + :type data: List[SimcoreNode] + """ + + self._data = data + + @property + def error(self) -> object: + """Gets the error of this InlineResponse2001. + + + :return: The error of this InlineResponse2001. + :rtype: object + """ + return self._error + + @error.setter + def error(self, error: object): + """Sets the error of this InlineResponse2001. + + + :param error: The error of this InlineResponse2001. + :type error: object + """ + + self._error = error diff --git a/services/director/src/simcore_service_director/rest/generated_code/models/nodemetav0_authors.py b/services/director/src/simcore_service_director/rest/generated_code/models/inline_response2001_authors.py similarity index 54% rename from services/director/src/simcore_service_director/rest/generated_code/models/nodemetav0_authors.py rename to services/director/src/simcore_service_director/rest/generated_code/models/inline_response2001_authors.py index 267e3d348da..a1e51bd7f74 100644 --- a/services/director/src/simcore_service_director/rest/generated_code/models/nodemetav0_authors.py +++ b/services/director/src/simcore_service_director/rest/generated_code/models/inline_response2001_authors.py @@ -9,114 +9,114 @@ from .. import util -class Nodemetav0Authors(Model): +class InlineResponse2001Authors(Model): """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). Do not edit the class manually. """ - def __init__(self, name: str=None, email: str=None, affiliation: str=None): # noqa: E501 - """Nodemetav0Authors - a model defined in OpenAPI + def __init__(self, affiliation: str=None, email: str=None, name: str=None): # noqa: E501 + """InlineResponse2001Authors - a model defined in OpenAPI - :param name: The name of this Nodemetav0Authors. # noqa: E501 - :type name: str - :param email: The email of this Nodemetav0Authors. # noqa: E501 - :type email: str - :param affiliation: The affiliation of this Nodemetav0Authors. # noqa: E501 + :param affiliation: The affiliation of this InlineResponse2001Authors. # noqa: E501 :type affiliation: str + :param email: The email of this InlineResponse2001Authors. # noqa: E501 + :type email: str + :param name: The name of this InlineResponse2001Authors. # noqa: E501 + :type name: str """ self.openapi_types = { - 'name': str, + 'affiliation': str, 'email': str, - 'affiliation': str + 'name': str } self.attribute_map = { - 'name': 'name', + 'affiliation': 'affiliation', 'email': 'email', - 'affiliation': 'affiliation' + 'name': 'name' } - self._name = name - self._email = email self._affiliation = affiliation + self._email = email + self._name = name @classmethod - def from_dict(cls, dikt) -> 'Nodemetav0Authors': + def from_dict(cls, dikt) -> 'InlineResponse2001Authors': """Returns the dict as a model :param dikt: A dict. :type: dict - :return: The nodemetav0_authors of this Nodemetav0Authors. # noqa: E501 - :rtype: Nodemetav0Authors + :return: The inline_response_200_1_authors of this InlineResponse2001Authors. # noqa: E501 + :rtype: InlineResponse2001Authors """ return util.deserialize_model(dikt, cls) @property - def name(self) -> str: - """Gets the name of this Nodemetav0Authors. + def affiliation(self) -> str: + """Gets the affiliation of this InlineResponse2001Authors. - Name of the author # noqa: E501 + Affiliation of the author # noqa: E501 - :return: The name of this Nodemetav0Authors. + :return: The affiliation of this InlineResponse2001Authors. :rtype: str """ - return self._name + return self._affiliation - @name.setter - def name(self, name: str): - """Sets the name of this Nodemetav0Authors. + @affiliation.setter + def affiliation(self, affiliation: str): + """Sets the affiliation of this InlineResponse2001Authors. - Name of the author # noqa: E501 + Affiliation of the author # noqa: E501 - :param name: The name of this Nodemetav0Authors. - :type name: str + :param affiliation: The affiliation of this InlineResponse2001Authors. + :type affiliation: str """ - self._name = name + self._affiliation = affiliation @property def email(self) -> str: - """Gets the email of this Nodemetav0Authors. + """Gets the email of this InlineResponse2001Authors. Email address # noqa: E501 - :return: The email of this Nodemetav0Authors. + :return: The email of this InlineResponse2001Authors. :rtype: str """ return self._email @email.setter def email(self, email: str): - """Sets the email of this Nodemetav0Authors. + """Sets the email of this InlineResponse2001Authors. Email address # noqa: E501 - :param email: The email of this Nodemetav0Authors. + :param email: The email of this InlineResponse2001Authors. :type email: str """ self._email = email @property - def affiliation(self) -> str: - """Gets the affiliation of this Nodemetav0Authors. + def name(self) -> str: + """Gets the name of this InlineResponse2001Authors. - Affiliation of the author # noqa: E501 + Name of the author # noqa: E501 - :return: The affiliation of this Nodemetav0Authors. + :return: The name of this InlineResponse2001Authors. :rtype: str """ - return self._affiliation + return self._name - @affiliation.setter - def affiliation(self, affiliation: str): - """Sets the affiliation of this Nodemetav0Authors. + @name.setter + def name(self, name: str): + """Sets the name of this InlineResponse2001Authors. - Affiliation of the author # noqa: E501 + Name of the author # noqa: E501 - :param affiliation: The affiliation of this Nodemetav0Authors. - :type affiliation: str + :param name: The name of this InlineResponse2001Authors. + :type name: str """ - self._affiliation = affiliation + self._name = name diff --git a/services/director/src/simcore_service_director/rest/generated_code/models/health_check.py b/services/director/src/simcore_service_director/rest/generated_code/models/inline_response200_data.py similarity index 55% rename from services/director/src/simcore_service_director/rest/generated_code/models/health_check.py rename to services/director/src/simcore_service_director/rest/generated_code/models/inline_response200_data.py index 4018484a35d..148fe672330 100644 --- a/services/director/src/simcore_service_director/rest/generated_code/models/health_check.py +++ b/services/director/src/simcore_service_director/rest/generated_code/models/inline_response200_data.py @@ -9,70 +9,91 @@ from .. import util -class HealthCheck(Model): +class InlineResponse200Data(Model): """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). Do not edit the class manually. """ - def __init__(self, name: str=None, status: str=None, api_version: str=None, version: str=None): # noqa: E501 - """HealthCheck - a model defined in OpenAPI + def __init__(self, api_version: str=None, name: str=None, status: str=None, version: str=None): # noqa: E501 + """InlineResponse200Data - a model defined in OpenAPI - :param name: The name of this HealthCheck. # noqa: E501 + :param api_version: The api_version of this InlineResponse200Data. # noqa: E501 + :type api_version: str + :param name: The name of this InlineResponse200Data. # noqa: E501 :type name: str - :param status: The status of this HealthCheck. # noqa: E501 + :param status: The status of this InlineResponse200Data. # noqa: E501 :type status: str - :param api_version: The api_version of this HealthCheck. # noqa: E501 - :type api_version: str - :param version: The version of this HealthCheck. # noqa: E501 + :param version: The version of this InlineResponse200Data. # noqa: E501 :type version: str """ self.openapi_types = { + 'api_version': str, 'name': str, 'status': str, - 'api_version': str, 'version': str } self.attribute_map = { + 'api_version': 'api_version', 'name': 'name', 'status': 'status', - 'api_version': 'api_version', 'version': 'version' } + self._api_version = api_version self._name = name self._status = status - self._api_version = api_version self._version = version @classmethod - def from_dict(cls, dikt) -> 'HealthCheck': + def from_dict(cls, dikt) -> 'InlineResponse200Data': """Returns the dict as a model :param dikt: A dict. :type: dict - :return: The HealthCheck of this HealthCheck. # noqa: E501 - :rtype: HealthCheck + :return: The inline_response_200_data of this InlineResponse200Data. # noqa: E501 + :rtype: InlineResponse200Data """ return util.deserialize_model(dikt, cls) + @property + def api_version(self) -> str: + """Gets the api_version of this InlineResponse200Data. + + + :return: The api_version of this InlineResponse200Data. + :rtype: str + """ + return self._api_version + + @api_version.setter + def api_version(self, api_version: str): + """Sets the api_version of this InlineResponse200Data. + + + :param api_version: The api_version of this InlineResponse200Data. + :type api_version: str + """ + + self._api_version = api_version + @property def name(self) -> str: - """Gets the name of this HealthCheck. + """Gets the name of this InlineResponse200Data. - :return: The name of this HealthCheck. + :return: The name of this InlineResponse200Data. :rtype: str """ return self._name @name.setter def name(self, name: str): - """Sets the name of this HealthCheck. + """Sets the name of this InlineResponse200Data. - :param name: The name of this HealthCheck. + :param name: The name of this InlineResponse200Data. :type name: str """ @@ -80,62 +101,41 @@ def name(self, name: str): @property def status(self) -> str: - """Gets the status of this HealthCheck. + """Gets the status of this InlineResponse200Data. - :return: The status of this HealthCheck. + :return: The status of this InlineResponse200Data. :rtype: str """ return self._status @status.setter def status(self, status: str): - """Sets the status of this HealthCheck. + """Sets the status of this InlineResponse200Data. - :param status: The status of this HealthCheck. + :param status: The status of this InlineResponse200Data. :type status: str """ self._status = status - @property - def api_version(self) -> str: - """Gets the api_version of this HealthCheck. - - - :return: The api_version of this HealthCheck. - :rtype: str - """ - return self._api_version - - @api_version.setter - def api_version(self, api_version: str): - """Sets the api_version of this HealthCheck. - - - :param api_version: The api_version of this HealthCheck. - :type api_version: str - """ - - self._api_version = api_version - @property def version(self) -> str: - """Gets the version of this HealthCheck. + """Gets the version of this InlineResponse200Data. - :return: The version of this HealthCheck. + :return: The version of this InlineResponse200Data. :rtype: str """ return self._version @version.setter def version(self, version: str): - """Sets the version of this HealthCheck. + """Sets the version of this InlineResponse200Data. - :param version: The version of this HealthCheck. + :param version: The version of this InlineResponse200Data. :type version: str """ diff --git a/services/director/src/simcore_service_director/rest/generated_code/models/inline_response201.py b/services/director/src/simcore_service_director/rest/generated_code/models/inline_response201.py new file mode 100644 index 00000000000..9d2fcdabadc --- /dev/null +++ b/services/director/src/simcore_service_director/rest/generated_code/models/inline_response201.py @@ -0,0 +1,91 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from .base_model_ import Model +from .inline_response201_data import InlineResponse201Data # noqa: F401,E501 +from .. import util + + +class InlineResponse201(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, data: InlineResponse201Data=None, error: object=None): # noqa: E501 + """InlineResponse201 - a model defined in OpenAPI + + :param data: The data of this InlineResponse201. # noqa: E501 + :type data: InlineResponse201Data + :param error: The error of this InlineResponse201. # noqa: E501 + :type error: object + """ + self.openapi_types = { + 'data': InlineResponse201Data, + 'error': object + } + + self.attribute_map = { + 'data': 'data', + 'error': 'error' + } + + self._data = data + self._error = error + + @classmethod + def from_dict(cls, dikt) -> 'InlineResponse201': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The inline_response_201 of this InlineResponse201. # noqa: E501 + :rtype: InlineResponse201 + """ + return util.deserialize_model(dikt, cls) + + @property + def data(self) -> InlineResponse201Data: + """Gets the data of this InlineResponse201. + + + :return: The data of this InlineResponse201. + :rtype: InlineResponse201Data + """ + return self._data + + @data.setter + def data(self, data: InlineResponse201Data): + """Sets the data of this InlineResponse201. + + + :param data: The data of this InlineResponse201. + :type data: InlineResponse201Data + """ + + self._data = data + + @property + def error(self) -> object: + """Gets the error of this InlineResponse201. + + + :return: The error of this InlineResponse201. + :rtype: object + """ + return self._error + + @error.setter + def error(self, error: object): + """Sets the error of this InlineResponse201. + + + :param error: The error of this InlineResponse201. + :type error: object + """ + + self._error = error diff --git a/services/director/src/simcore_service_director/rest/generated_code/models/running_service.py b/services/director/src/simcore_service_director/rest/generated_code/models/inline_response201_data.py similarity index 61% rename from services/director/src/simcore_service_director/rest/generated_code/models/running_service.py rename to services/director/src/simcore_service_director/rest/generated_code/models/inline_response201_data.py index d5158783224..16062589f10 100644 --- a/services/director/src/simcore_service_director/rest/generated_code/models/running_service.py +++ b/services/director/src/simcore_service_director/rest/generated_code/models/inline_response201_data.py @@ -9,120 +9,116 @@ from .. import util -class RunningService(Model): +class InlineResponse201Data(Model): """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). Do not edit the class manually. """ - def __init__(self, published_port: int=None, entry_point: str=None, service_uuid: str=None): # noqa: E501 - """RunningService - a model defined in OpenAPI + def __init__(self, entry_point: str=None, published_port: int=None, service_uuid: str=None): # noqa: E501 + """InlineResponse201Data - a model defined in OpenAPI - :param published_port: The published_port of this RunningService. # noqa: E501 - :type published_port: int - :param entry_point: The entry_point of this RunningService. # noqa: E501 + :param entry_point: The entry_point of this InlineResponse201Data. # noqa: E501 :type entry_point: str - :param service_uuid: The service_uuid of this RunningService. # noqa: E501 + :param published_port: The published_port of this InlineResponse201Data. # noqa: E501 + :type published_port: int + :param service_uuid: The service_uuid of this InlineResponse201Data. # noqa: E501 :type service_uuid: str """ self.openapi_types = { - 'published_port': int, 'entry_point': str, + 'published_port': int, 'service_uuid': str } self.attribute_map = { - 'published_port': 'published_port', 'entry_point': 'entry_point', + 'published_port': 'published_port', 'service_uuid': 'service_uuid' } - self._published_port = published_port self._entry_point = entry_point + self._published_port = published_port self._service_uuid = service_uuid @classmethod - def from_dict(cls, dikt) -> 'RunningService': + def from_dict(cls, dikt) -> 'InlineResponse201Data': """Returns the dict as a model :param dikt: A dict. :type: dict - :return: The RunningService of this RunningService. # noqa: E501 - :rtype: RunningService + :return: The inline_response_201_data of this InlineResponse201Data. # noqa: E501 + :rtype: InlineResponse201Data """ return util.deserialize_model(dikt, cls) + @property + def entry_point(self) -> str: + """Gets the entry_point of this InlineResponse201Data. + + The entry point where the service provides its interface if specified # noqa: E501 + + :return: The entry_point of this InlineResponse201Data. + :rtype: str + """ + return self._entry_point + + @entry_point.setter + def entry_point(self, entry_point: str): + """Sets the entry_point of this InlineResponse201Data. + + The entry point where the service provides its interface if specified # noqa: E501 + + :param entry_point: The entry_point of this InlineResponse201Data. + :type entry_point: str + """ + + self._entry_point = entry_point + @property def published_port(self) -> int: - """Gets the published_port of this RunningService. + """Gets the published_port of this InlineResponse201Data. The ports where the service provides its interface # noqa: E501 - :return: The published_port of this RunningService. + :return: The published_port of this InlineResponse201Data. :rtype: int """ return self._published_port @published_port.setter def published_port(self, published_port: int): - """Sets the published_port of this RunningService. + """Sets the published_port of this InlineResponse201Data. The ports where the service provides its interface # noqa: E501 - :param published_port: The published_port of this RunningService. + :param published_port: The published_port of this InlineResponse201Data. :type published_port: int """ - if published_port is None: - raise ValueError("Invalid value for `published_port`, must not be `None`") # noqa: E501 if published_port is not None and published_port < 1: # noqa: E501 raise ValueError("Invalid value for `published_port`, must be a value greater than or equal to `1`") # noqa: E501 self._published_port = published_port - @property - def entry_point(self) -> str: - """Gets the entry_point of this RunningService. - - The entry point where the service provides its interface if specified # noqa: E501 - - :return: The entry_point of this RunningService. - :rtype: str - """ - return self._entry_point - - @entry_point.setter - def entry_point(self, entry_point: str): - """Sets the entry_point of this RunningService. - - The entry point where the service provides its interface if specified # noqa: E501 - - :param entry_point: The entry_point of this RunningService. - :type entry_point: str - """ - - self._entry_point = entry_point - @property def service_uuid(self) -> str: - """Gets the service_uuid of this RunningService. + """Gets the service_uuid of this InlineResponse201Data. The UUID attached to this service # noqa: E501 - :return: The service_uuid of this RunningService. + :return: The service_uuid of this InlineResponse201Data. :rtype: str """ return self._service_uuid @service_uuid.setter def service_uuid(self, service_uuid: str): - """Sets the service_uuid of this RunningService. + """Sets the service_uuid of this InlineResponse201Data. The UUID attached to this service # noqa: E501 - :param service_uuid: The service_uuid of this RunningService. + :param service_uuid: The service_uuid of this InlineResponse201Data. :type service_uuid: str """ - if service_uuid is None: - raise ValueError("Invalid value for `service_uuid`, must not be `None`") # noqa: E501 self._service_uuid = service_uuid diff --git a/services/director/src/simcore_service_director/rest/generated_code/models/inline_response204.py b/services/director/src/simcore_service_director/rest/generated_code/models/inline_response204.py new file mode 100644 index 00000000000..9e8d981e519 --- /dev/null +++ b/services/director/src/simcore_service_director/rest/generated_code/models/inline_response204.py @@ -0,0 +1,90 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from .base_model_ import Model +from .. import util + + +class InlineResponse204(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, data: object=None, error: object=None): # noqa: E501 + """InlineResponse204 - a model defined in OpenAPI + + :param data: The data of this InlineResponse204. # noqa: E501 + :type data: object + :param error: The error of this InlineResponse204. # noqa: E501 + :type error: object + """ + self.openapi_types = { + 'data': object, + 'error': object + } + + self.attribute_map = { + 'data': 'data', + 'error': 'error' + } + + self._data = data + self._error = error + + @classmethod + def from_dict(cls, dikt) -> 'InlineResponse204': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The inline_response_204 of this InlineResponse204. # noqa: E501 + :rtype: InlineResponse204 + """ + return util.deserialize_model(dikt, cls) + + @property + def data(self) -> object: + """Gets the data of this InlineResponse204. + + + :return: The data of this InlineResponse204. + :rtype: object + """ + return self._data + + @data.setter + def data(self, data: object): + """Sets the data of this InlineResponse204. + + + :param data: The data of this InlineResponse204. + :type data: object + """ + + self._data = data + + @property + def error(self) -> object: + """Gets the error of this InlineResponse204. + + + :return: The error of this InlineResponse204. + :rtype: object + """ + return self._error + + @error.setter + def error(self, error: object): + """Sets the error of this InlineResponse204. + + + :param error: The error of this InlineResponse204. + :type error: object + """ + + self._error = error diff --git a/services/director/src/simcore_service_director/rest/generated_code/models/inline_response_default.py b/services/director/src/simcore_service_director/rest/generated_code/models/inline_response_default.py new file mode 100644 index 00000000000..83c82c89c24 --- /dev/null +++ b/services/director/src/simcore_service_director/rest/generated_code/models/inline_response_default.py @@ -0,0 +1,91 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from .base_model_ import Model +from .inline_response_default_error import InlineResponseDefaultError # noqa: F401,E501 +from .. import util + + +class InlineResponseDefault(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, data: object=None, error: InlineResponseDefaultError=None): # noqa: E501 + """InlineResponseDefault - a model defined in OpenAPI + + :param data: The data of this InlineResponseDefault. # noqa: E501 + :type data: object + :param error: The error of this InlineResponseDefault. # noqa: E501 + :type error: InlineResponseDefaultError + """ + self.openapi_types = { + 'data': object, + 'error': InlineResponseDefaultError + } + + self.attribute_map = { + 'data': 'data', + 'error': 'error' + } + + self._data = data + self._error = error + + @classmethod + def from_dict(cls, dikt) -> 'InlineResponseDefault': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The inline_response_default of this InlineResponseDefault. # noqa: E501 + :rtype: InlineResponseDefault + """ + return util.deserialize_model(dikt, cls) + + @property + def data(self) -> object: + """Gets the data of this InlineResponseDefault. + + + :return: The data of this InlineResponseDefault. + :rtype: object + """ + return self._data + + @data.setter + def data(self, data: object): + """Sets the data of this InlineResponseDefault. + + + :param data: The data of this InlineResponseDefault. + :type data: object + """ + + self._data = data + + @property + def error(self) -> InlineResponseDefaultError: + """Gets the error of this InlineResponseDefault. + + + :return: The error of this InlineResponseDefault. + :rtype: InlineResponseDefaultError + """ + return self._error + + @error.setter + def error(self, error: InlineResponseDefaultError): + """Sets the error of this InlineResponseDefault. + + + :param error: The error of this InlineResponseDefault. + :type error: InlineResponseDefaultError + """ + + self._error = error diff --git a/services/director/src/simcore_service_director/rest/generated_code/models/error.py b/services/director/src/simcore_service_director/rest/generated_code/models/inline_response_default_error.py similarity index 57% rename from services/director/src/simcore_service_director/rest/generated_code/models/error.py rename to services/director/src/simcore_service_director/rest/generated_code/models/inline_response_default_error.py index 7a900ce7433..ffc1727d67e 100644 --- a/services/director/src/simcore_service_director/rest/generated_code/models/error.py +++ b/services/director/src/simcore_service_director/rest/generated_code/models/inline_response_default_error.py @@ -9,116 +9,112 @@ from .. import util -class Error(Model): +class InlineResponseDefaultError(Model): """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). Do not edit the class manually. """ - def __init__(self, message: str=None, errors: List[object]=None, status: int=None): # noqa: E501 - """Error - a model defined in OpenAPI + def __init__(self, errors: List[object]=None, message: str=None, status: int=None): # noqa: E501 + """InlineResponseDefaultError - a model defined in OpenAPI - :param message: The message of this Error. # noqa: E501 - :type message: str - :param errors: The errors of this Error. # noqa: E501 + :param errors: The errors of this InlineResponseDefaultError. # noqa: E501 :type errors: List[object] - :param status: The status of this Error. # noqa: E501 + :param message: The message of this InlineResponseDefaultError. # noqa: E501 + :type message: str + :param status: The status of this InlineResponseDefaultError. # noqa: E501 :type status: int """ self.openapi_types = { - 'message': str, 'errors': List[object], + 'message': str, 'status': int } self.attribute_map = { - 'message': 'message', 'errors': 'errors', + 'message': 'message', 'status': 'status' } - self._message = message self._errors = errors + self._message = message self._status = status @classmethod - def from_dict(cls, dikt) -> 'Error': + def from_dict(cls, dikt) -> 'InlineResponseDefaultError': """Returns the dict as a model :param dikt: A dict. :type: dict - :return: The Error of this Error. # noqa: E501 - :rtype: Error + :return: The inline_response_default_error of this InlineResponseDefaultError. # noqa: E501 + :rtype: InlineResponseDefaultError """ return util.deserialize_model(dikt, cls) @property - def message(self) -> str: - """Gets the message of this Error. + def errors(self) -> List[object]: + """Gets the errors of this InlineResponseDefaultError. - Error message # noqa: E501 - :return: The message of this Error. - :rtype: str + :return: The errors of this InlineResponseDefaultError. + :rtype: List[object] """ - return self._message + return self._errors - @message.setter - def message(self, message: str): - """Sets the message of this Error. + @errors.setter + def errors(self, errors: List[object]): + """Sets the errors of this InlineResponseDefaultError. - Error message # noqa: E501 - :param message: The message of this Error. - :type message: str + :param errors: The errors of this InlineResponseDefaultError. + :type errors: List[object] """ - if message is None: - raise ValueError("Invalid value for `message`, must not be `None`") # noqa: E501 - self._message = message + self._errors = errors @property - def errors(self) -> List[object]: - """Gets the errors of this Error. + def message(self) -> str: + """Gets the message of this InlineResponseDefaultError. + Error message # noqa: E501 - :return: The errors of this Error. - :rtype: List[object] + :return: The message of this InlineResponseDefaultError. + :rtype: str """ - return self._errors + return self._message - @errors.setter - def errors(self, errors: List[object]): - """Sets the errors of this Error. + @message.setter + def message(self, message: str): + """Sets the message of this InlineResponseDefaultError. + Error message # noqa: E501 - :param errors: The errors of this Error. - :type errors: List[object] + :param message: The message of this InlineResponseDefaultError. + :type message: str """ - self._errors = errors + self._message = message @property def status(self) -> int: - """Gets the status of this Error. + """Gets the status of this InlineResponseDefaultError. Error code # noqa: E501 - :return: The status of this Error. + :return: The status of this InlineResponseDefaultError. :rtype: int """ return self._status @status.setter def status(self, status: int): - """Sets the status of this Error. + """Sets the status of this InlineResponseDefaultError. Error code # noqa: E501 - :param status: The status of this Error. + :param status: The status of this InlineResponseDefaultError. :type status: int """ - if status is None: - raise ValueError("Invalid value for `status`, must not be `None`") # noqa: E501 self._status = status diff --git a/services/director/src/simcore_service_director/rest/generated_code/models/response204_enveloped.py b/services/director/src/simcore_service_director/rest/generated_code/models/response204_enveloped.py deleted file mode 100644 index 66478a60ed5..00000000000 --- a/services/director/src/simcore_service_director/rest/generated_code/models/response204_enveloped.py +++ /dev/null @@ -1,90 +0,0 @@ -# coding: utf-8 - -from __future__ import absolute_import -from datetime import date, datetime # noqa: F401 - -from typing import List, Dict # noqa: F401 - -from .base_model_ import Model -from .. import util - - -class Response204Enveloped(Model): - """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - - Do not edit the class manually. - """ - - def __init__(self, data: str=None, status: int=None): # noqa: E501 - """Response204Enveloped - a model defined in OpenAPI - - :param data: The data of this Response204Enveloped. # noqa: E501 - :type data: str - :param status: The status of this Response204Enveloped. # noqa: E501 - :type status: int - """ - self.openapi_types = { - 'data': str, - 'status': int - } - - self.attribute_map = { - 'data': 'data', - 'status': 'status' - } - - self._data = data - self._status = status - - @classmethod - def from_dict(cls, dikt) -> 'Response204Enveloped': - """Returns the dict as a model - - :param dikt: A dict. - :type: dict - :return: The Response204Enveloped of this Response204Enveloped. # noqa: E501 - :rtype: Response204Enveloped - """ - return util.deserialize_model(dikt, cls) - - @property - def data(self) -> str: - """Gets the data of this Response204Enveloped. - - - :return: The data of this Response204Enveloped. - :rtype: str - """ - return self._data - - @data.setter - def data(self, data: str): - """Sets the data of this Response204Enveloped. - - - :param data: The data of this Response204Enveloped. - :type data: str - """ - - self._data = data - - @property - def status(self) -> int: - """Gets the status of this Response204Enveloped. - - - :return: The status of this Response204Enveloped. - :rtype: int - """ - return self._status - - @status.setter - def status(self, status: int): - """Sets the status of this Response204Enveloped. - - - :param status: The status of this Response204Enveloped. - :type status: int - """ - - self._status = status diff --git a/services/director/src/simcore_service_director/rest/generated_code/models/running_service_enveloped.py b/services/director/src/simcore_service_director/rest/generated_code/models/running_service_enveloped.py deleted file mode 100644 index bc39ee9b117..00000000000 --- a/services/director/src/simcore_service_director/rest/generated_code/models/running_service_enveloped.py +++ /dev/null @@ -1,91 +0,0 @@ -# coding: utf-8 - -from __future__ import absolute_import -from datetime import date, datetime # noqa: F401 - -from typing import List, Dict # noqa: F401 - -from .base_model_ import Model -from .running_service import RunningService # noqa: F401,E501 -from .. import util - - -class RunningServiceEnveloped(Model): - """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - - Do not edit the class manually. - """ - - def __init__(self, data: RunningService=None, status: int=None): # noqa: E501 - """RunningServiceEnveloped - a model defined in OpenAPI - - :param data: The data of this RunningServiceEnveloped. # noqa: E501 - :type data: RunningService - :param status: The status of this RunningServiceEnveloped. # noqa: E501 - :type status: int - """ - self.openapi_types = { - 'data': RunningService, - 'status': int - } - - self.attribute_map = { - 'data': 'data', - 'status': 'status' - } - - self._data = data - self._status = status - - @classmethod - def from_dict(cls, dikt) -> 'RunningServiceEnveloped': - """Returns the dict as a model - - :param dikt: A dict. - :type: dict - :return: The RunningServiceEnveloped of this RunningServiceEnveloped. # noqa: E501 - :rtype: RunningServiceEnveloped - """ - return util.deserialize_model(dikt, cls) - - @property - def data(self) -> RunningService: - """Gets the data of this RunningServiceEnveloped. - - - :return: The data of this RunningServiceEnveloped. - :rtype: RunningService - """ - return self._data - - @data.setter - def data(self, data: RunningService): - """Sets the data of this RunningServiceEnveloped. - - - :param data: The data of this RunningServiceEnveloped. - :type data: RunningService - """ - - self._data = data - - @property - def status(self) -> int: - """Gets the status of this RunningServiceEnveloped. - - - :return: The status of this RunningServiceEnveloped. - :rtype: int - """ - return self._status - - @status.setter - def status(self, status: int): - """Sets the status of this RunningServiceEnveloped. - - - :param status: The status of this RunningServiceEnveloped. - :type status: int - """ - - self._status = status diff --git a/services/director/src/simcore_service_director/rest/generated_code/models/services_enveloped.py b/services/director/src/simcore_service_director/rest/generated_code/models/services_enveloped.py deleted file mode 100644 index e927f5cf5e1..00000000000 --- a/services/director/src/simcore_service_director/rest/generated_code/models/services_enveloped.py +++ /dev/null @@ -1,91 +0,0 @@ -# coding: utf-8 - -from __future__ import absolute_import -from datetime import date, datetime # noqa: F401 - -from typing import List, Dict # noqa: F401 - -from .base_model_ import Model -from .node_meta_v0 import NodeMetaV0 # noqa: F401,E501 -from .. import util - - -class ServicesEnveloped(Model): - """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - - Do not edit the class manually. - """ - - def __init__(self, data: List[NodeMetaV0]=None, status: int=None): # noqa: E501 - """ServicesEnveloped - a model defined in OpenAPI - - :param data: The data of this ServicesEnveloped. # noqa: E501 - :type data: List[NodeMetaV0] - :param status: The status of this ServicesEnveloped. # noqa: E501 - :type status: int - """ - self.openapi_types = { - 'data': List[NodeMetaV0], - 'status': int - } - - self.attribute_map = { - 'data': 'data', - 'status': 'status' - } - - self._data = data - self._status = status - - @classmethod - def from_dict(cls, dikt) -> 'ServicesEnveloped': - """Returns the dict as a model - - :param dikt: A dict. - :type: dict - :return: The ServicesEnveloped of this ServicesEnveloped. # noqa: E501 - :rtype: ServicesEnveloped - """ - return util.deserialize_model(dikt, cls) - - @property - def data(self) -> List[NodeMetaV0]: - """Gets the data of this ServicesEnveloped. - - - :return: The data of this ServicesEnveloped. - :rtype: List[NodeMetaV0] - """ - return self._data - - @data.setter - def data(self, data: List[NodeMetaV0]): - """Sets the data of this ServicesEnveloped. - - - :param data: The data of this ServicesEnveloped. - :type data: List[NodeMetaV0] - """ - - self._data = data - - @property - def status(self) -> int: - """Gets the status of this ServicesEnveloped. - - - :return: The status of this ServicesEnveloped. - :rtype: int - """ - return self._status - - @status.setter - def status(self, status: int): - """Sets the status of this ServicesEnveloped. - - - :param status: The status of this ServicesEnveloped. - :type status: int - """ - - self._status = status diff --git a/services/director/src/simcore_service_director/rest/generated_code/models/node_meta_v0.py b/services/director/src/simcore_service_director/rest/generated_code/models/simcore_node.py similarity index 56% rename from services/director/src/simcore_service_director/rest/generated_code/models/node_meta_v0.py rename to services/director/src/simcore_service_director/rest/generated_code/models/simcore_node.py index 34146bf5bfc..c89699dde22 100644 --- a/services/director/src/simcore_service_director/rest/generated_code/models/node_meta_v0.py +++ b/services/director/src/simcore_service_director/rest/generated_code/models/simcore_node.py @@ -6,311 +6,295 @@ from typing import List, Dict # noqa: F401 from .base_model_ import Model -from .nodemetav0_authors import Nodemetav0Authors # noqa: F401,E501 +from .inline_response2001_authors import InlineResponse2001Authors # noqa: F401,E501 import re # noqa: F401,E501 from .. import util -class NodeMetaV0(Model): +class SimcoreNode(Model): """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). Do not edit the class manually. """ - def __init__(self, key: str=None, version: str=None, type: str=None, name: str=None, description: str=None, authors: List[Nodemetav0Authors]=None, contact: str=None, inputs: object=None, outputs: object=None): # noqa: E501 - """NodeMetaV0 - a model defined in OpenAPI + def __init__(self, authors: List[InlineResponse2001Authors]=None, contact: str=None, description: str=None, inputs: object=None, key: str=None, name: str=None, outputs: object=None, type: str=None, version: str=None): # noqa: E501 + """SimcoreNode - a model defined in OpenAPI - :param key: The key of this NodeMetaV0. # noqa: E501 - :type key: str - :param version: The version of this NodeMetaV0. # noqa: E501 - :type version: str - :param type: The type of this NodeMetaV0. # noqa: E501 - :type type: str - :param name: The name of this NodeMetaV0. # noqa: E501 - :type name: str - :param description: The description of this NodeMetaV0. # noqa: E501 - :type description: str - :param authors: The authors of this NodeMetaV0. # noqa: E501 - :type authors: List[Nodemetav0Authors] - :param contact: The contact of this NodeMetaV0. # noqa: E501 + :param authors: The authors of this SimcoreNode. # noqa: E501 + :type authors: List[InlineResponse2001Authors] + :param contact: The contact of this SimcoreNode. # noqa: E501 :type contact: str - :param inputs: The inputs of this NodeMetaV0. # noqa: E501 + :param description: The description of this SimcoreNode. # noqa: E501 + :type description: str + :param inputs: The inputs of this SimcoreNode. # noqa: E501 :type inputs: object - :param outputs: The outputs of this NodeMetaV0. # noqa: E501 + :param key: The key of this SimcoreNode. # noqa: E501 + :type key: str + :param name: The name of this SimcoreNode. # noqa: E501 + :type name: str + :param outputs: The outputs of this SimcoreNode. # noqa: E501 :type outputs: object + :param type: The type of this SimcoreNode. # noqa: E501 + :type type: str + :param version: The version of this SimcoreNode. # noqa: E501 + :type version: str """ self.openapi_types = { - 'key': str, - 'version': str, - 'type': str, - 'name': str, - 'description': str, - 'authors': List[Nodemetav0Authors], + 'authors': List[InlineResponse2001Authors], 'contact': str, + 'description': str, 'inputs': object, - 'outputs': object + 'key': str, + 'name': str, + 'outputs': object, + 'type': str, + 'version': str } self.attribute_map = { - 'key': 'key', - 'version': 'version', - 'type': 'type', - 'name': 'name', - 'description': 'description', 'authors': 'authors', 'contact': 'contact', + 'description': 'description', 'inputs': 'inputs', - 'outputs': 'outputs' + 'key': 'key', + 'name': 'name', + 'outputs': 'outputs', + 'type': 'type', + 'version': 'version' } - self._key = key - self._version = version - self._type = type - self._name = name - self._description = description self._authors = authors self._contact = contact + self._description = description self._inputs = inputs + self._key = key + self._name = name self._outputs = outputs + self._type = type + self._version = version @classmethod - def from_dict(cls, dikt) -> 'NodeMetaV0': + def from_dict(cls, dikt) -> 'SimcoreNode': """Returns the dict as a model :param dikt: A dict. :type: dict - :return: The node-meta-v0 of this NodeMetaV0. # noqa: E501 - :rtype: NodeMetaV0 + :return: The simcore node of this SimcoreNode. # noqa: E501 + :rtype: SimcoreNode """ return util.deserialize_model(dikt, cls) @property - def key(self) -> str: - """Gets the key of this NodeMetaV0. + def authors(self) -> List[InlineResponse2001Authors]: + """Gets the authors of this SimcoreNode. - distinctive name for the node based on the docker registry path # noqa: E501 - :return: The key of this NodeMetaV0. - :rtype: str + :return: The authors of this SimcoreNode. + :rtype: List[InlineResponse2001Authors] """ - return self._key + return self._authors - @key.setter - def key(self, key: str): - """Sets the key of this NodeMetaV0. + @authors.setter + def authors(self, authors: List[InlineResponse2001Authors]): + """Sets the authors of this SimcoreNode. - distinctive name for the node based on the docker registry path # noqa: E501 - :param key: The key of this NodeMetaV0. - :type key: str + :param authors: The authors of this SimcoreNode. + :type authors: List[InlineResponse2001Authors] """ - if key is None: - raise ValueError("Invalid value for `key`, must not be `None`") # noqa: E501 - if key is not None and not re.search('^(simcore)\/(services)\/(comp|dynamic)(\/[^\\s\/]+)+$', key): # noqa: E501 - raise ValueError("Invalid value for `key`, must be a follow pattern or equal to `/^(simcore)\/(services)\/(comp|dynamic)(\/[^\\s\/]+)+$/`") # noqa: E501 - self._key = key + self._authors = authors @property - def version(self) -> str: - """Gets the version of this NodeMetaV0. + def contact(self) -> str: + """Gets the contact of this SimcoreNode. - semantic version number # noqa: E501 + email to correspond to the authors about the node # noqa: E501 - :return: The version of this NodeMetaV0. + :return: The contact of this SimcoreNode. :rtype: str """ - return self._version + return self._contact - @version.setter - def version(self, version: str): - """Sets the version of this NodeMetaV0. + @contact.setter + def contact(self, contact: str): + """Sets the contact of this SimcoreNode. - semantic version number # noqa: E501 + email to correspond to the authors about the node # noqa: E501 - :param version: The version of this NodeMetaV0. - :type version: str + :param contact: The contact of this SimcoreNode. + :type contact: str """ - if version is None: - raise ValueError("Invalid value for `version`, must not be `None`") # noqa: E501 - if version is not None and not re.search('^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$', version): # noqa: E501 - raise ValueError("Invalid value for `version`, must be a follow pattern or equal to `/^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$/`") # noqa: E501 - self._version = version + self._contact = contact @property - def type(self) -> str: - """Gets the type of this NodeMetaV0. + def description(self) -> str: + """Gets the description of this SimcoreNode. - service type # noqa: E501 + human readable description of the purpose of the node # noqa: E501 - :return: The type of this NodeMetaV0. + :return: The description of this SimcoreNode. :rtype: str """ - return self._type + return self._description - @type.setter - def type(self, type: str): - """Sets the type of this NodeMetaV0. + @description.setter + def description(self, description: str): + """Sets the description of this SimcoreNode. - service type # noqa: E501 + human readable description of the purpose of the node # noqa: E501 - :param type: The type of this NodeMetaV0. - :type type: str + :param description: The description of this SimcoreNode. + :type description: str """ - allowed_values = ["computational", "dynamic"] # noqa: E501 - if type not in allowed_values: - raise ValueError( - "Invalid value for `type` ({0}), must be one of {1}" - .format(type, allowed_values) - ) - self._type = type + self._description = description @property - def name(self) -> str: - """Gets the name of this NodeMetaV0. + def inputs(self) -> object: + """Gets the inputs of this SimcoreNode. - short, human readable name for the node # noqa: E501 + definition of the inputs of this node # noqa: E501 - :return: The name of this NodeMetaV0. - :rtype: str + :return: The inputs of this SimcoreNode. + :rtype: object """ - return self._name + return self._inputs - @name.setter - def name(self, name: str): - """Sets the name of this NodeMetaV0. + @inputs.setter + def inputs(self, inputs: object): + """Sets the inputs of this SimcoreNode. - short, human readable name for the node # noqa: E501 + definition of the inputs of this node # noqa: E501 - :param name: The name of this NodeMetaV0. - :type name: str + :param inputs: The inputs of this SimcoreNode. + :type inputs: object """ - if name is None: - raise ValueError("Invalid value for `name`, must not be `None`") # noqa: E501 - self._name = name + self._inputs = inputs @property - def description(self) -> str: - """Gets the description of this NodeMetaV0. + def key(self) -> str: + """Gets the key of this SimcoreNode. - human readable description of the purpose of the node # noqa: E501 + distinctive name for the node based on the docker registry path # noqa: E501 - :return: The description of this NodeMetaV0. + :return: The key of this SimcoreNode. :rtype: str """ - return self._description + return self._key - @description.setter - def description(self, description: str): - """Sets the description of this NodeMetaV0. + @key.setter + def key(self, key: str): + """Sets the key of this SimcoreNode. - human readable description of the purpose of the node # noqa: E501 + distinctive name for the node based on the docker registry path # noqa: E501 - :param description: The description of this NodeMetaV0. - :type description: str + :param key: The key of this SimcoreNode. + :type key: str """ - if description is None: - raise ValueError("Invalid value for `description`, must not be `None`") # noqa: E501 + if key is not None and not re.search('^(simcore)\/(services)\/(comp|dynamic)(\/[^\\s\/]+)+$', key): # noqa: E501 + raise ValueError("Invalid value for `key`, must be a follow pattern or equal to `/^(simcore)\/(services)\/(comp|dynamic)(\/[^\\s\/]+)+$/`") # noqa: E501 - self._description = description + self._key = key @property - def authors(self) -> List[Nodemetav0Authors]: - """Gets the authors of this NodeMetaV0. + def name(self) -> str: + """Gets the name of this SimcoreNode. + short, human readable name for the node # noqa: E501 - :return: The authors of this NodeMetaV0. - :rtype: List[Nodemetav0Authors] + :return: The name of this SimcoreNode. + :rtype: str """ - return self._authors + return self._name - @authors.setter - def authors(self, authors: List[Nodemetav0Authors]): - """Sets the authors of this NodeMetaV0. + @name.setter + def name(self, name: str): + """Sets the name of this SimcoreNode. + short, human readable name for the node # noqa: E501 - :param authors: The authors of this NodeMetaV0. - :type authors: List[Nodemetav0Authors] + :param name: The name of this SimcoreNode. + :type name: str """ - if authors is None: - raise ValueError("Invalid value for `authors`, must not be `None`") # noqa: E501 - self._authors = authors + self._name = name @property - def contact(self) -> str: - """Gets the contact of this NodeMetaV0. + def outputs(self) -> object: + """Gets the outputs of this SimcoreNode. - email to correspond to the authors about the node # noqa: E501 + definition of the outputs of this node # noqa: E501 - :return: The contact of this NodeMetaV0. - :rtype: str + :return: The outputs of this SimcoreNode. + :rtype: object """ - return self._contact + return self._outputs - @contact.setter - def contact(self, contact: str): - """Sets the contact of this NodeMetaV0. + @outputs.setter + def outputs(self, outputs: object): + """Sets the outputs of this SimcoreNode. - email to correspond to the authors about the node # noqa: E501 + definition of the outputs of this node # noqa: E501 - :param contact: The contact of this NodeMetaV0. - :type contact: str + :param outputs: The outputs of this SimcoreNode. + :type outputs: object """ - if contact is None: - raise ValueError("Invalid value for `contact`, must not be `None`") # noqa: E501 - self._contact = contact + self._outputs = outputs @property - def inputs(self) -> object: - """Gets the inputs of this NodeMetaV0. + def type(self) -> str: + """Gets the type of this SimcoreNode. - definition of the inputs of this node # noqa: E501 + service type # noqa: E501 - :return: The inputs of this NodeMetaV0. - :rtype: object + :return: The type of this SimcoreNode. + :rtype: str """ - return self._inputs + return self._type - @inputs.setter - def inputs(self, inputs: object): - """Sets the inputs of this NodeMetaV0. + @type.setter + def type(self, type: str): + """Sets the type of this SimcoreNode. - definition of the inputs of this node # noqa: E501 + service type # noqa: E501 - :param inputs: The inputs of this NodeMetaV0. - :type inputs: object + :param type: The type of this SimcoreNode. + :type type: str """ - if inputs is None: - raise ValueError("Invalid value for `inputs`, must not be `None`") # noqa: E501 + allowed_values = ["computational", "dynamic"] # noqa: E501 + if type not in allowed_values: + raise ValueError( + "Invalid value for `type` ({0}), must be one of {1}" + .format(type, allowed_values) + ) - self._inputs = inputs + self._type = type @property - def outputs(self) -> object: - """Gets the outputs of this NodeMetaV0. + def version(self) -> str: + """Gets the version of this SimcoreNode. - definition of the outputs of this node # noqa: E501 + semantic version number # noqa: E501 - :return: The outputs of this NodeMetaV0. - :rtype: object + :return: The version of this SimcoreNode. + :rtype: str """ - return self._outputs + return self._version - @outputs.setter - def outputs(self, outputs: object): - """Sets the outputs of this NodeMetaV0. + @version.setter + def version(self, version: str): + """Sets the version of this SimcoreNode. - definition of the outputs of this node # noqa: E501 + semantic version number # noqa: E501 - :param outputs: The outputs of this NodeMetaV0. - :type outputs: object + :param version: The version of this SimcoreNode. + :type version: str """ - if outputs is None: - raise ValueError("Invalid value for `outputs`, must not be `None`") # noqa: E501 + if version is not None and not re.search('^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$', version): # noqa: E501 + raise ValueError("Invalid value for `version`, must be a follow pattern or equal to `/^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$/`") # noqa: E501 - self._outputs = outputs + self._version = version diff --git a/services/director/src/simcore_service_director/rest/generated_code/routing.py b/services/director/src/simcore_service_director/rest/generated_code/routing.py index 675c667aee8..1f8466c20a1 100644 --- a/services/director/src/simcore_service_director/rest/generated_code/routing.py +++ b/services/director/src/simcore_service_director/rest/generated_code/routing.py @@ -19,8 +19,6 @@ from .. import handlers from .models.base_model_ import Model -from .models.error import Error -from .models.error_enveloped import ErrorEnveloped log = logging.getLogger(__name__) @@ -33,16 +31,14 @@ async def __handle_errors(request, handler): except ValidationError as ex: # aiohttp apiset errors log.exception("error happened in handling route") - error = Error(status=ex.status, message=ex.to_tree()) - error_enveloped = ErrorEnveloped(data=error, status=ex.status_code) - error_dict = error_enveloped.to_dict() - return web.json_response(error_dict, status=ex.status) + error = dict(status=ex.status, message=ex.to_tree()) + error_enveloped = dict(error=error) + return web.json_response(error_enveloped, status=ex.status) except web.HTTPError as ex: log.exception("error happened in handling route") - error = Error(status=ex.status, message=str(ex.reason)) - error_enveloped = ErrorEnveloped(data=error, status=ex.status_code) - error_dict = error_enveloped.to_dict() - return web.json_response(error_dict, status=ex.status) + error = dict(status=ex.status, message=str(ex.reason)) + error_enveloped = dict(data=error) + return web.json_response(error_enveloped, status=ex.status) def create_web_app(base_folder, spec_file, additional_middlewares = None): @@ -78,8 +74,8 @@ def create_web_app(base_folder, spec_file, additional_middlewares = None): router.include( spec=Path(base_folder / spec_file), operationId_mapping=opmap, - name='v1', # name to access in swagger-ui, - basePath="/v1" # BUG: in apiset with openapi 3.0.0 [Github bug entry](https://github.com/aamalev/aiohttp_apiset/issues/45) + name='v0', # name to access in swagger-ui, + basePath="/v0" # BUG: in apiset with openapi 3.0.0 [Github bug entry](https://github.com/aamalev/aiohttp_apiset/issues/45) ) return app diff --git a/services/director/src/simcore_service_director/rest/handlers.py b/services/director/src/simcore_service_director/rest/handlers.py index 76d461c413c..80f99f36b6c 100644 --- a/services/director/src/simcore_service_director/rest/handlers.py +++ b/services/director/src/simcore_service_director/rest/handlers.py @@ -2,17 +2,12 @@ import pkg_resources import yaml -from aiohttp import web_exceptions +from aiohttp import web_exceptions, web from simcore_service_director import (config, exceptions, producer, registry_proxy, resources) from . import (api_converters, node_validator) -from .generated_code.models import (HealthCheck, HealthCheckEnveloped, - NodeMetaV0, Response204Enveloped, - RunningService, RunningServiceEnveloped, - ServicesEnveloped) - log = logging.getLogger(__name__) async def root_get(request): # pylint:disable=unused-argument @@ -21,12 +16,12 @@ async def root_get(request): # pylint:disable=unused-argument with resources.stream(resources.RESOURCE_OPEN_API) as file_ptr: api_dict = yaml.load(file_ptr) - service_health = HealthCheck( + service_health = dict( name=distb.project_name, status="SERVICE_RUNNING", api_version=api_dict["info"]["version"], version=distb.version) - return HealthCheckEnveloped(data=service_health, status=200).to_dict() + return web.json_response(dict(data=service_health)) async def services_get(request, service_type=None): # pylint:disable=unused-argument log.debug("Client does services_get request %s with service_type %s", request, service_type) @@ -34,10 +29,9 @@ async def services_get(request, service_type=None): # pylint:disable=unused-arg services = [] if not service_type or "computational" in service_type: services.extend(_list_services(registry_proxy.list_computational_services)) - if not service_type or "interactive" in service_type: services.extend(_list_services(registry_proxy.list_interactive_services)) - return ServicesEnveloped(data=services, status=200).to_dict() + return web.json_response(data=dict(data=services)) except exceptions.RegistryConnectionError as err: raise web_exceptions.HTTPUnauthorized(reason=str(err)) except Exception as err: @@ -49,7 +43,7 @@ async def services_by_key_version_get(request, service_key, service_version): # services = [registry_proxy.get_service_details(service_key, service_version)] if config.CONVERT_OLD_API: services = [api_converters.convert_service_from_old_api(x) for x in services] - return ServicesEnveloped(data=services, status=200).to_dict() + return web.json_response(data=dict(data=services)) except exceptions.ServiceNotAvailableError as err: raise web_exceptions.HTTPNotFound(reason=str(err)) except exceptions.RegistryConnectionError as err: @@ -63,9 +57,7 @@ def _list_services(list_service_fct): if config.CONVERT_OLD_API: services = [api_converters.convert_service_from_old_api(x) for x in services if not node_validator.is_service_valid(x)] services = node_validator.validate_nodes(services) - - service_descs = [NodeMetaV0.from_dict(x) for x in services] - return service_descs + return services async def running_interactive_services_post(request, service_key, service_uuid, service_tag): # pylint:disable=unused-argument log.debug("Client does running_interactive_services_post request %s with service_key %s, service_uuid %s and service_tag %s", @@ -73,8 +65,7 @@ async def running_interactive_services_post(request, service_key, service_uuid, try: service = producer.start_service(service_key, service_tag, service_uuid) - running_service = RunningService.from_dict(service) - return RunningServiceEnveloped(data=running_service, status=201).to_dict() + return web.json_response(data=dict(data=service), status=201) except exceptions.ServiceStartTimeoutError as err: raise web_exceptions.HTTPInternalServerError(reason=str(err)) except exceptions.ServiceNotAvailableError as err: @@ -95,7 +86,7 @@ async def running_interactive_services_get(request, service_uuid): # pylint:dis except Exception as err: raise web_exceptions.HTTPInternalServerError(reason=str(err)) - return Response204Enveloped(status=204).to_dict() + return web.json_response(status=204) async def running_interactive_services_delete(request, service_uuid): # pylint:disable=unused-argument log.debug("Client does running_interactive_services_delete request %s with service_uuid %s", request, service_uuid) @@ -106,4 +97,4 @@ async def running_interactive_services_delete(request, service_uuid): # pylint: except Exception as err: raise web_exceptions.HTTPInternalServerError(reason=str(err)) - return Response204Enveloped(status=204).to_dict() + return web.json_response(status=204) diff --git a/services/director/requirements/test.txt b/services/director/tests/requirements.txt similarity index 100% rename from services/director/requirements/test.txt rename to services/director/tests/requirements.txt diff --git a/services/director/tests/test_handlers.py b/services/director/tests/test_handlers.py index 8a1b7af23db..c65f1e51d75 100644 --- a/services/director/tests/test_handlers.py +++ b/services/director/tests/test_handlers.py @@ -1,48 +1,45 @@ import json import uuid -from pathlib import Path import pytest from aiohttp import web_exceptions -from simcore_service_director import config, rest +from simcore_service_director import config, resources, rest from helpers import json_schema_validator +API_VERSIONS = resources.listdir(resources.RESOURCE_OPENAPI_ROOT) @pytest.mark.asyncio async def test_root_get(): fake_request = "fake request" - response = await rest.handlers.root_get(fake_request) - assert "data" in response - assert "status" in response - assert response["status"] == 200 + web_response = await rest.handlers.root_get(fake_request) + assert web_response.content_type == "application/json" + assert web_response.status == 200 + healthcheck_enveloped = json.loads(web_response.text) + assert "data" in healthcheck_enveloped - healthcheck_enveloped = rest.models.HealthCheckEnveloped.from_dict(response) - assert healthcheck_enveloped.status == 200 - assert isinstance(healthcheck_enveloped.data, rest.models.HealthCheck) + assert isinstance(healthcheck_enveloped["data"], dict) - healthcheck = healthcheck_enveloped.data - assert healthcheck.name == "simcore-service-director" - assert healthcheck.status == "SERVICE_RUNNING" - assert healthcheck.version == "0.1.0" - assert healthcheck.api_version == "1.0.0" + healthcheck = healthcheck_enveloped["data"] + assert healthcheck["name"] == "simcore-service-director" + assert healthcheck["status"] == "SERVICE_RUNNING" + assert healthcheck["version"] == "0.1.0" + assert healthcheck["api_version"] == "1.0.0" def _check_services(created_services, services, schema_version="v1"): assert len(created_services) == len(services) created_service_descriptions = [x["service_description"] for x in created_services] - # TODO: use resources! - json_schema_path = Path(__file__).parent.parent / "src/simcore_service_director/oas3/v1/components/schemas/node-meta-v0.0.1.json" + json_schema_path = resources.get_path(resources.RESOURCE_NODE_SCHEMA) assert json_schema_path.exists() == True with json_schema_path.open() as file_pt: service_schema = json.load(file_pt) - for service in services: - assert isinstance(service, rest.models.NodeMetaV0) + for service in services: if schema_version == "v1": - assert created_service_descriptions.count(service.to_dict()) == 1 - json_schema_validator.validate_instance_object(service.to_dict(), service_schema) + assert created_service_descriptions.count(service) == 1 + json_schema_validator.validate_instance_object(service, service_schema) @pytest.mark.asyncio async def test_services_get(docker_registry, push_services): @@ -50,53 +47,85 @@ async def test_services_get(docker_registry, push_services): fake_request = "fake request" # no registry defined with pytest.raises(web_exceptions.HTTPInternalServerError, message="Expecting HTTP Internal Error as no registry URL is defined"): - services_enveloped = rest.models.ServicesEnveloped.from_dict(await rest.handlers.services_get(fake_request)) + services_enveloped = await rest.handlers.services_get(fake_request) # wrong registry defined config.REGISTRY_URL = "blahblah" with pytest.raises(web_exceptions.HTTPInternalServerError, message="Expecting HTTP Internal Error as SSL is enabled by default"): - services_enveloped = rest.models.ServicesEnveloped.from_dict(await rest.handlers.services_get(fake_request)) + services_enveloped = await rest.handlers.services_get(fake_request) # right registry defined config.REGISTRY_URL = docker_registry with pytest.raises(web_exceptions.HTTPInternalServerError, message="Expecting HTTP Internal Error as SSL is enabled by default"): - services_enveloped = rest.models.ServicesEnveloped.from_dict(await rest.handlers.services_get(fake_request)) + services_enveloped = await rest.handlers.services_get(fake_request) # no SSL config.REGISTRY_SSL = False # empty case - services_enveloped = rest.models.ServicesEnveloped.from_dict(await rest.handlers.services_get(fake_request)) - assert services_enveloped.status == 200 - assert isinstance(services_enveloped.data, list) - services = services_enveloped.data + web_response = await rest.handlers.services_get(fake_request) + assert web_response.status == 200 + assert web_response.content_type == "application/json" + services_enveloped = json.loads(web_response.text) + assert isinstance(services_enveloped["data"], list) + services = services_enveloped["data"] _check_services([], services) # some services created_services = push_services(3,2) - services_enveloped = rest.models.ServicesEnveloped.from_dict(await rest.handlers.services_get(fake_request)) - assert services_enveloped.status == 200 - assert isinstance(services_enveloped.data, list) - services = services_enveloped.data + web_response = await rest.handlers.services_get(fake_request) + assert web_response.status == 200 + assert web_response.content_type == "application/json" + services_enveloped = json.loads(web_response.text) + assert isinstance(services_enveloped["data"], list) + services = services_enveloped["data"] _check_services(created_services, services) + web_response = await rest.handlers.services_get(fake_request, "blahblah") + assert web_response.status == 200 + assert web_response.content_type == "application/json" + services_enveloped = json.loads(web_response.text) + assert isinstance(services_enveloped["data"], list) + services = services_enveloped["data"] + assert len(services) == 0 + + web_response = await rest.handlers.services_get(fake_request, "computational") + assert web_response.status == 200 + assert web_response.content_type == "application/json" + services_enveloped = json.loads(web_response.text) + assert isinstance(services_enveloped["data"], list) + services = services_enveloped["data"] + assert len(services) == 3 + + web_response = await rest.handlers.services_get(fake_request, "interactive") + assert web_response.status == 200 + assert web_response.content_type == "application/json" + services_enveloped = json.loads(web_response.text) + assert isinstance(services_enveloped["data"], list) + services = services_enveloped["data"] + assert len(services) == 2 + @pytest.mark.asyncio async def test_v0_services_conversion_to_new(configure_registry_access, push_v0_schema_services): #pylint: disable=W0613, W0621 fake_request = "fake request" created_services = push_v0_schema_services(3,2) assert len(created_services) == 5 - services_enveloped = rest.models.ServicesEnveloped.from_dict(await rest.handlers.services_get(fake_request)) - assert services_enveloped.status == 200 - assert isinstance(services_enveloped.data, list) - services = services_enveloped.data + web_response = await rest.handlers.services_get(fake_request) + assert web_response.status == 200 + assert web_response.content_type == "application/json" + services_enveloped = json.loads(web_response.text) + assert isinstance(services_enveloped["data"], list) + services = services_enveloped["data"] # ensure old style services are not retrieved assert len(services) == 0 # check conversion config.CONVERT_OLD_API = True - services_enveloped = rest.models.ServicesEnveloped.from_dict(await rest.handlers.services_get(fake_request)) - assert services_enveloped.status == 200 - assert isinstance(services_enveloped.data, list) - services = services_enveloped.data + web_response = await rest.handlers.services_get(fake_request) + assert web_response.status == 200 + assert web_response.content_type == "application/json" + services_enveloped = json.loads(web_response.text) + assert isinstance(services_enveloped["data"], list) + services = services_enveloped["data"] _check_services(created_services, services, "v0") @pytest.mark.asyncio @@ -105,39 +134,81 @@ async def test_v1_services_with_old_conversion(configure_registry_access, push_s created_services = push_services(3,2) assert len(created_services) == 5 # no conversion, shoult return the exact same services - services_enveloped = rest.models.ServicesEnveloped.from_dict(await rest.handlers.services_get(fake_request)) - assert services_enveloped.status == 200 - assert isinstance(services_enveloped.data, list) - services = services_enveloped.data + web_response = await rest.handlers.services_get(fake_request) + assert web_response.status == 200 + assert web_response.content_type == "application/json" + services_enveloped = json.loads(web_response.text) + assert isinstance(services_enveloped["data"], list) + services = services_enveloped["data"] _check_services(created_services, services) # with conversion enabled, should return no services config.CONVERT_OLD_API = True - services_enveloped = rest.models.ServicesEnveloped.from_dict(await rest.handlers.services_get(fake_request)) - assert services_enveloped.status == 200 - assert isinstance(services_enveloped.data, list) - services = services_enveloped.data + web_response = await rest.handlers.services_get(fake_request) + assert web_response.status == 200 + assert web_response.content_type == "application/json" + services_enveloped = json.loads(web_response.text) + assert isinstance(services_enveloped["data"], list) + services = services_enveloped["data"] assert len(services) == 0 @pytest.mark.asyncio async def test_services_by_key_version_get(configure_registry_access, push_services): #pylint: disable=W0613, W0621 fake_request = "fake request" + + with pytest.raises(web_exceptions.HTTPInternalServerError, message="Expecting internal server error"): + web_response = await rest.handlers.services_by_key_version_get(fake_request, None, None) + + with pytest.raises(web_exceptions.HTTPInternalServerError, message="Expecting internal server error"): + web_response = await rest.handlers.services_by_key_version_get(fake_request, "whatever", None) + + with pytest.raises(web_exceptions.HTTPNotFound, message="Expecting not found error"): + web_response = await rest.handlers.services_by_key_version_get(fake_request, "whatever", "ofwhateverversion") + created_services = push_services(3,2) - assert len(created_services) == 5 + assert len(created_services) == 5 + retrieved_services = [] for created_service in created_services: service_description = created_service["service_description"] - services_enveloped = rest.models.ServicesEnveloped.from_dict(await rest.handlers.services_by_key_version_get(fake_request, service_description["key"], service_description["version"])) - assert services_enveloped.status == 200 - assert isinstance(services_enveloped.data, list) - services = services_enveloped.data + web_response = await rest.handlers.services_by_key_version_get(fake_request, service_description["key"], service_description["version"]) + assert web_response.status == 200 + assert web_response.content_type == "application/json" + services_enveloped = json.loads(web_response.text) + assert isinstance(services_enveloped["data"], list) + services = services_enveloped["data"] assert len(services) == 1 retrieved_services.append(services[0]) _check_services(created_services, retrieved_services) async def _start_get_stop_services(push_services): fake_request = "fake request" + + with pytest.raises(web_exceptions.HTTPInternalServerError, message="Expecting internal server error"): + web_response = await rest.handlers.running_interactive_services_post(fake_request, None, None, None) + + with pytest.raises(web_exceptions.HTTPInternalServerError, message="Expecting internal server error"): + web_response = await rest.handlers.running_interactive_services_post(fake_request, "None", None, None) + + with pytest.raises(web_exceptions.HTTPNotFound, message="Expecting not found error"): + web_response = await rest.handlers.running_interactive_services_post(fake_request, "None", "None", None) + + with pytest.raises(web_exceptions.HTTPNotFound, message="Expecting not found error"): + web_response = await rest.handlers.running_interactive_services_post(fake_request, "None", "None", "ablah") + + with pytest.raises(web_exceptions.HTTPInternalServerError, message="Expecting internal server error"): + web_response = await rest.handlers.running_interactive_services_get(fake_request, None) + + with pytest.raises(web_exceptions.HTTPNotFound, message="Expecting not found error"): + web_response = await rest.handlers.running_interactive_services_get(fake_request, "service_uuid") + + with pytest.raises(web_exceptions.HTTPInternalServerError, message="Expecting internal server error"): + web_response = await rest.handlers.running_interactive_services_delete(fake_request, None) + + with pytest.raises(web_exceptions.HTTPNotFound, message="Expecting not found error"): + web_response = await rest.handlers.running_interactive_services_delete(fake_request, "service_uuid") + created_services = push_services(0,2) assert len(created_services) == 2 for created_service in created_services: @@ -146,19 +217,23 @@ async def _start_get_stop_services(push_services): service_tag = service_description["version"] service_uuid = str(uuid.uuid4()) # start the service - running_service_enveloped = rest.models.RunningServiceEnveloped.from_dict(await rest.handlers.running_interactive_services_post(fake_request, service_key, service_uuid, service_tag)) - assert running_service_enveloped.status == 201 - assert isinstance(running_service_enveloped.data, rest.models.RunningService) + web_response = await rest.handlers.running_interactive_services_post(fake_request, service_key, service_uuid, service_tag) + assert web_response.status == 201 + assert web_response.content_type == "application/json" + running_service_enveloped = json.loads(web_response.text) + assert isinstance(running_service_enveloped["data"], dict) # get the service - response = rest.models.Response204Enveloped.from_dict(await rest.handlers.running_interactive_services_get(fake_request, service_uuid)) - assert response.status == 204 - assert response.data is None + web_response = await rest.handlers.running_interactive_services_get(fake_request, service_uuid) + assert web_response.status == 204 + assert web_response.content_type == "application/json" + assert web_response.text is None # stop the service - response = rest.models.Response204Enveloped.from_dict(await rest.handlers.running_interactive_services_delete(fake_request, service_uuid)) - assert response.status == 204 - assert response.data is None + web_response = await rest.handlers.running_interactive_services_delete(fake_request, service_uuid) + assert web_response.status == 204 + assert web_response.content_type == "application/json" + assert web_response.text is None @pytest.mark.asyncio async def test_running_services_post_and_delete_no_swarm(configure_registry_access, push_services): #pylint: disable=W0613, W0621 diff --git a/services/director/tests/test_json_schemas.py b/services/director/tests/test_json_schemas.py new file mode 100644 index 00000000000..1d3403d1477 --- /dev/null +++ b/services/director/tests/test_json_schemas.py @@ -0,0 +1,31 @@ +import json +from pathlib import Path + +import pytest +from jsonschema import ( + SchemaError, + ValidationError, + validate) + +from simcore_service_director import resources + +API_VERSIONS = resources.listdir(resources.RESOURCE_OPENAPI_ROOT) + +def validate_individual_schemas(list_of_paths): + for spec_file_path in list_of_paths: + assert spec_file_path.exists() + with spec_file_path.open() as file_ptr: + schema_specs = json.load(file_ptr) + try: + dummy_instance = {} + with pytest.raises(ValidationError, message="Expected a Json schema validation error"): + validate(dummy_instance, schema_specs) + except SchemaError as err: + pytest.fail(err.message) + +@pytest.mark.parametrize('version', API_VERSIONS) +def test_valid_individual_json_schemas_specs(version): + name = "{root}/{version}/schemas".format(root=resources.RESOURCE_OPENAPI_ROOT, version=version) + schemas_folder_path = resources.get_path(name) + + validate_individual_schemas(Path(schemas_folder_path).rglob("*.json")) diff --git a/services/director/tests/test_openapi_schemas.py b/services/director/tests/test_openapi_schemas.py new file mode 100644 index 00000000000..746a3c1ce4f --- /dev/null +++ b/services/director/tests/test_openapi_schemas.py @@ -0,0 +1,67 @@ +from pathlib import Path + +import pytest +import yaml + +from openapi_spec_validator import validate_spec +from openapi_spec_validator.exceptions import OpenAPIValidationError + +from simcore_service_director import resources + +API_VERSIONS = resources.listdir(resources.RESOURCE_OPENAPI_ROOT) + +def correct_schema_local_references(schema_specs): + for key, value in schema_specs.items(): + if isinstance(value, dict): + correct_schema_local_references(value) + elif "$ref" in key: + if str(value).startswith("#/"): + # correct the reference + new_value = str(value).replace("#/", "#/components/schemas/") + schema_specs[key] = new_value + +def add_namespace_for_converted_schemas(schema_specs): + # schemas converted from jsonschema do not have an overarching namespace. + # the openapi validator does not like this + # we use the jsonschema title to create a fake namespace + fake_schema_specs = { + "FakeName": schema_specs + } + return fake_schema_specs + +def validate_individual_schemas(list_of_paths): + fake_openapi_headers = { + "openapi": "3.0.0", + "info":{ + "title": "An include file to define sortable attributes", + "version": "1.0.0" + }, + "paths": {}, + "components": { + "parameters":{}, + "schemas":{} + } + } + + for spec_file_path in list_of_paths: + assert spec_file_path.exists() + # only consider schemas + if not "openapi.yaml" in str(spec_file_path.name) and "schemas" in str(spec_file_path): + with spec_file_path.open() as file_ptr: + schema_specs = yaml.load(file_ptr) + # correct local references + correct_schema_local_references(schema_specs) + if str(spec_file_path).endswith("-converted.yaml"): + schema_specs = add_namespace_for_converted_schemas(schema_specs) + fake_openapi_headers["components"]["schemas"] = schema_specs + try: + validate_spec(fake_openapi_headers, spec_url=spec_file_path.as_uri()) + except OpenAPIValidationError as err: + pytest.fail(err.message) + +@pytest.mark.parametrize('version', API_VERSIONS) +def test_valid_individual_openapi_schemas_specs(version): + name = "{root}/{version}/schemas".format(root=resources.RESOURCE_OPENAPI_ROOT, version=version) + schemas_folder_path = resources.get_path(name) + validate_individual_schemas(Path(schemas_folder_path).rglob("*.yaml")) + validate_individual_schemas(Path(schemas_folder_path).rglob("*.yml")) diff --git a/services/docker-compose.deploy.devel.yml b/services/docker-compose.deploy.devel.yml index b63fda18b49..fed20b4e26f 100644 --- a/services/docker-compose.deploy.devel.yml +++ b/services/docker-compose.deploy.devel.yml @@ -3,6 +3,12 @@ # FIXME: remove explicit dns version: '3.4' services: + apihub: + image: services_apihub:dev + deploy: + placement: + constraints: + - node.platform.os == linux director: #image: masu.speag.com/simcore/workbench/director:2.3 image: services_director:dev diff --git a/services/docker-compose.deploy.yml b/services/docker-compose.deploy.yml index 48fc17e46d7..76c3fd040cf 100644 --- a/services/docker-compose.deploy.yml +++ b/services/docker-compose.deploy.yml @@ -3,6 +3,12 @@ # FIXME: remove explicit dns version: '3.4' services: + apihub: + image: services_apihub:latest + deploy: + placement: + constraints: + - node.platform.os == linux director: #image: masu.speag.com/simcore/workbench/director:2.3 image: services_director:latest diff --git a/services/docker-compose.devel.yml b/services/docker-compose.devel.yml index 101fdc3555f..e085be4567e 100644 --- a/services/docker-compose.devel.yml +++ b/services/docker-compose.devel.yml @@ -1,6 +1,13 @@ # USAGE: docker-compose -f docker-compose.yml -f docker-compose.devel.yml ... version: '3.4' services: + apihub: + image: services_apihub:dev + build: + target: development + volumes: + - '../apis:/srv/http/apis' + #-------------------------------------------------------------------- director: image: services_director:dev build: diff --git a/services/docker-compose.swarm.yml.template b/services/docker-compose.swarm.yml.template index 2a4982b75e2..c9ff0f602f7 100644 --- a/services/docker-compose.swarm.yml.template +++ b/services/docker-compose.swarm.yml.template @@ -3,6 +3,15 @@ # FIXME: remove explicit dns version: '3.4' services: + apihub: + image: masu.speag.com/simcore/apihub:3.9 + deploy: + placement: + constraints: + - node.platform.os == linux + ports: + - '8043:8043' + director: image: masu.speag.com/simcore/workbench/director:3.9 #image: services_director:latest diff --git a/services/docker-compose.yml b/services/docker-compose.yml index 54faab03ee0..98d212c3217 100644 --- a/services/docker-compose.yml +++ b/services/docker-compose.yml @@ -1,5 +1,13 @@ version: '3.4' -services: +services: + apihub: + build: + context: ../ + dockerfile: services/apihub/Dockerfile + target: production + ports: + - '8043:8043' +#-------------------------------------------------------------------- director: build: context: ../ @@ -132,8 +140,7 @@ services: - "5000:5000" volumes: - registry:/var/lib/registry - - #-------------------------------------------------------------------- + #-------------------------------------------------------------------- volumes: input: output: diff --git a/services/dy-modeling/client/source/class/qxapp/Application.js b/services/dy-modeling/client/source/class/qxapp/Application.js index 3808643dc97..b22c6c38183 100644 --- a/services/dy-modeling/client/source/class/qxapp/Application.js +++ b/services/dy-modeling/client/source/class/qxapp/Application.js @@ -79,30 +79,30 @@ qx.Class.define("qxapp.Application", { const menuBarHeight = 35; const avaiBarHeight = 55; - this._menuBar = new qxapp.components.MenuBar( + this._menuBar = new qxapp.component.MenuBar( docWidth, menuBarHeight, this._appModel.getColors().getMenuBar() .getBackground(), this._appModel.getColors().getMenuBar() .getFont()); - this._userMenu = new qxapp.components.UserMenu( + this._userMenu = new qxapp.component.UserMenu( this._appModel, this._appModel.getColors().getMenuBar() .getBackground(), this._appModel.getColors().getMenuBar() .getFont()); - this.__availableServicesBar = new qxapp.components.AvailableServices( + this.__availableServicesBar = new qxapp.component.AvailableServices( docWidth, avaiBarHeight, this._appModel.getColors().getToolBar() .getBackground(), this._appModel.getColors().getToolBar() .getFont()); - this.__threeView = new qxapp.components.ThreeView( + this.__threeView = new qxapp.component.ThreeView( docWidth, docHeight, this._appModel.getColors().get3DView() .getBackground()); - this.__entityList = new qxapp.components.EntityList( + this.__entityList = new qxapp.component.EntityList( 250, 300, this._appModel.getColors().getSettingsView() .getBackground(), this._appModel.getColors().getSettingsView() @@ -442,7 +442,7 @@ qx.Class.define("qxapp.Application", { }, _showPreferences: function() { - let preferencesDlg = new qxapp.components.Preferences( + let preferencesDlg = new qxapp.component.Preferences( this._appModel, 250, 300, this._appModel.getColors().getSettingsView() .getBackground(), this._appModel.getColors().getSettingsView() diff --git a/services/dy-modeling/client/source/class/qxapp/components/AvailableServices.js b/services/dy-modeling/client/source/class/qxapp/components/AvailableServices.js index 2c3f2872602..d6134d9d643 100644 --- a/services/dy-modeling/client/source/class/qxapp/components/AvailableServices.js +++ b/services/dy-modeling/client/source/class/qxapp/components/AvailableServices.js @@ -1,6 +1,6 @@ /* global window */ -qx.Class.define("qxapp.components.AvailableServices", { +qx.Class.define("qxapp.component.AvailableServices", { extend: qx.ui.container.Composite, include: [qx.locale.MTranslation], diff --git a/services/dy-modeling/client/source/class/qxapp/components/EntityList.js b/services/dy-modeling/client/source/class/qxapp/components/EntityList.js index ad84e614f79..8c67e663280 100644 --- a/services/dy-modeling/client/source/class/qxapp/components/EntityList.js +++ b/services/dy-modeling/client/source/class/qxapp/components/EntityList.js @@ -1,7 +1,7 @@ /* eslint no-warning-comments: "off" */ /* eslint no-underscore-dangle: ["error", { "allowAfterThis": true, "enforceInMethodNames": true, "allow": ["__widgetChildren"] }] */ -qx.Class.define("qxapp.components.EntityList", { +qx.Class.define("qxapp.component.EntityList", { extend: qx.ui.window.Window, include: [qx.locale.MTranslation], diff --git a/services/dy-modeling/client/source/class/qxapp/components/MenuBar.js b/services/dy-modeling/client/source/class/qxapp/components/MenuBar.js index 6f6dbeb4440..c5f8b434e5c 100644 --- a/services/dy-modeling/client/source/class/qxapp/components/MenuBar.js +++ b/services/dy-modeling/client/source/class/qxapp/components/MenuBar.js @@ -1,6 +1,6 @@ /* global window */ -qx.Class.define("qxapp.components.MenuBar", { +qx.Class.define("qxapp.component.MenuBar", { extend: qx.ui.container.Composite, include: [qx.locale.MTranslation], diff --git a/services/dy-modeling/client/source/class/qxapp/components/Preferences.js b/services/dy-modeling/client/source/class/qxapp/components/Preferences.js index 53cd53ebdf6..964c5f63c16 100644 --- a/services/dy-modeling/client/source/class/qxapp/components/Preferences.js +++ b/services/dy-modeling/client/source/class/qxapp/components/Preferences.js @@ -1,4 +1,4 @@ -qx.Class.define("qxapp.components.Preferences", { +qx.Class.define("qxapp.component.Preferences", { extend: qx.ui.window.Window, include: [qx.locale.MTranslation], diff --git a/services/dy-modeling/client/source/class/qxapp/components/ThreeView.js b/services/dy-modeling/client/source/class/qxapp/components/ThreeView.js index 9b9dcff4133..208a08d2acb 100644 --- a/services/dy-modeling/client/source/class/qxapp/components/ThreeView.js +++ b/services/dy-modeling/client/source/class/qxapp/components/ThreeView.js @@ -7,7 +7,7 @@ const TOOL_ACTIVE = 1; const ENTITY_PICKING = 2; const FACE_PICKING = 3; -qx.Class.define("qxapp.components.ThreeView", { +qx.Class.define("qxapp.component.ThreeView", { extend: qx.ui.container.Composite, construct : function(width, height, backgroundColor) { diff --git a/services/dy-modeling/client/source/class/qxapp/components/UserMenu.js b/services/dy-modeling/client/source/class/qxapp/components/UserMenu.js index 09caa68d877..6b1f9abdb22 100644 --- a/services/dy-modeling/client/source/class/qxapp/components/UserMenu.js +++ b/services/dy-modeling/client/source/class/qxapp/components/UserMenu.js @@ -1,4 +1,4 @@ -qx.Class.define("qxapp.components.UserMenu", { +qx.Class.define("qxapp.component.UserMenu", { extend: qx.ui.container.Composite, include : [qx.locale.MTranslation], diff --git a/services/sidecar/boot.sh b/services/sidecar/boot.sh old mode 100755 new mode 100644 diff --git a/services/sidecar/docker/entrypoint.sh b/services/sidecar/docker/entrypoint.sh old mode 100755 new mode 100644 diff --git a/services/web/client/package-lock.json b/services/web/client/package-lock.json new file mode 100644 index 00000000000..b743c2409b9 --- /dev/null +++ b/services/web/client/package-lock.json @@ -0,0 +1,5654 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "@octokit/rest": { + "version": "15.11.1", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-15.11.1.tgz", + "integrity": "sha512-+sXsSKUtZlbKaHZx7sCqpeJ1q2ZhzaResXoFA5MJIxy3RhsD1JMenNxALoDSO5UIT+IgW4v00ky7I2XwVMKCUg==", + "requires": { + "before-after-hook": "1.1.0", + "btoa-lite": "1.0.0", + "debug": "3.1.0", + "http-proxy-agent": "2.1.0", + "https-proxy-agent": "2.2.1", + "lodash": "4.17.10", + "node-fetch": "2.2.0", + "url-template": "2.0.8" + }, + "dependencies": { + "node-fetch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.2.0.tgz", + "integrity": "sha512-OayFWziIxiHY8bCUyLX6sTpDH8Jsbp4FfYd1j1f7vZyfgkcOnAyM4oQR16f8a0s7Gl/viMGRey8eScYk4V4EZA==" + } + } + }, + "@qooxdoo/preset-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@qooxdoo/preset-env/-/preset-env-1.0.0.tgz", + "integrity": "sha512-fNabl9rL3U+y17//q1LlUozxAJHHuE4MNrk9FxOSrcxtxiAopaeLJcCBzLV7uZiMk0qcuRH4mrFVL48Yeu1EiA==", + "requires": { + "babel-plugin-check-es2015-constants": "6.22.0", + "babel-plugin-syntax-trailing-function-commas": "6.22.0", + "babel-plugin-transform-async-to-generator": "6.24.1", + "babel-plugin-transform-es2015-arrow-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoping": "6.15.0", + "babel-plugin-transform-es2015-classes": "6.24.1", + "babel-plugin-transform-es2015-computed-properties": "6.24.1", + "babel-plugin-transform-es2015-destructuring": "6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "6.24.1", + "babel-plugin-transform-es2015-for-of": "6.23.0", + "babel-plugin-transform-es2015-function-name": "6.24.1", + "babel-plugin-transform-es2015-literals": "6.22.0", + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-plugin-transform-es2015-modules-commonjs": "6.26.2", + "babel-plugin-transform-es2015-modules-systemjs": "6.24.1", + "babel-plugin-transform-es2015-modules-umd": "6.24.1", + "babel-plugin-transform-es2015-object-super": "6.24.1", + "babel-plugin-transform-es2015-parameters": "6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "6.24.1", + "babel-plugin-transform-es2015-spread": "6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "6.24.1", + "babel-plugin-transform-es2015-template-literals": "6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "6.24.1", + "babel-plugin-transform-exponentiation-operator": "6.24.1", + "babel-plugin-transform-regenerator": "6.26.0", + "browserslist": "2.11.3", + "invariant": "2.2.4", + "semver": "5.5.1" + } + }, + "JSV": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz", + "integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c=" + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "requires": { + "mime-types": "2.1.20", + "negotiator": "0.6.1" + } + }, + "acorn": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.2.tgz", + "integrity": "sha512-cJrKCNcr2kv8dlDnbw+JPUGjHZzo4myaxOLmpOX8a+rgX94YeTcTMv/LFJUSByRpc+i4GgVnnhLxvMu/2Y+rqw==" + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "requires": { + "acorn": "3.3.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" + } + } + }, + "agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "requires": { + "es6-promisify": "5.0.0" + }, + "dependencies": { + "es6-promise": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "4.2.4" + } + } + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=" + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" + }, + "ansi-escapes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==" + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "requires": { + "micromatch": "2.3.11", + "normalize-path": "2.1.1" + } + }, + "app-module-path": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/app-module-path/-/app-module-path-2.2.0.tgz", + "integrity": "sha1-ZBqlXft9am8KgUHEucCqULbCTdU=" + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.3.6" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "1.0.3" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "requires": { + "arr-flatten": "1.1.0" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "2.1.2" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "ast-transform": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/ast-transform/-/ast-transform-0.0.0.tgz", + "integrity": "sha1-dJRAWIh9goPhidlUYAlHvJj+AGI=", + "requires": { + "escodegen": "1.2.0", + "esprima": "1.0.4", + "through": "2.3.8" + }, + "dependencies": { + "escodegen": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.2.0.tgz", + "integrity": "sha1-Cd55Z3kcyVi3+Jot220jRRrzJ+E=", + "requires": { + "esprima": "1.0.4", + "estraverse": "1.5.1", + "esutils": "1.0.0", + "source-map": "0.1.43" + } + }, + "esprima": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", + "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=" + }, + "estraverse": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.5.1.tgz", + "integrity": "sha1-hno+jlip+EYYr7bC3bzZFrfLr3E=" + }, + "esutils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz", + "integrity": "sha1-gVHTWOIMisx/t0XnRywAJf5JZXA=" + }, + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "optional": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "ast-types": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.7.8.tgz", + "integrity": "sha1-kC0uDWDQcb3NRtwRXhgJ7RHBOKk=" + }, + "async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", + "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "requires": { + "lodash": "4.17.10" + } + }, + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=" + }, + "async-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" + }, + "axios": { + "version": "0.15.3", + "resolved": "http://registry.npmjs.org/axios/-/axios-0.15.3.tgz", + "integrity": "sha1-LJ1jiy4ZGgjqHWzJiOrda6W9wFM=", + "requires": { + "follow-redirects": "1.0.0" + } + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } + }, + "babel-core": { + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", + "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", + "requires": { + "babel-code-frame": "6.26.0", + "babel-generator": "6.26.1", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "convert-source-map": "1.6.0", + "debug": "2.6.9", + "json5": "0.5.1", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", + "private": "0.1.8", + "slash": "1.0.0", + "source-map": "0.5.7" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "babel-eslint": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-6.1.2.tgz", + "integrity": "sha1-UpNBn+NnLWZZjTJ9qWlFZ7pqXy8=", + "requires": { + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash.assign": "4.2.0", + "lodash.pickby": "4.6.0" + } + }, + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "requires": { + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.10", + "source-map": "0.5.7", + "trim-right": "1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" + } + } + }, + "babel-helper-builder-binary-assignment-operator-visitor": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", + "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", + "requires": { + "babel-helper-explode-assignable-expression": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-call-delegate": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-define-map": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", + "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.10" + } + }, + "babel-helper-explode-assignable-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", + "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", + "requires": { + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "requires": { + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-hoist-variables": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-optimise-call-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", + "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.10" + } + }, + "babel-helper-remap-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", + "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-replace-supers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", + "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "requires": { + "babel-helper-optimise-call-expression": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-check-es2015-constants": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-syntax-async-functions": { + "version": "6.13.0", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=" + }, + "babel-plugin-syntax-exponentiation-operator": { + "version": "6.13.0", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", + "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=" + }, + "babel-plugin-syntax-trailing-function-commas": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", + "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=" + }, + "babel-plugin-transform-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", + "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", + "requires": { + "babel-helper-remap-async-to-generator": "6.24.1", + "babel-plugin-syntax-async-functions": "6.13.0", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-arrow-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", + "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", + "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-block-scoping": { + "version": "6.15.0", + "resolved": "http://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.15.0.tgz", + "integrity": "sha1-W0Q8oUK+jR22qMKuQvUZWLZrcPY=", + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.10" + } + }, + "babel-plugin-transform-es2015-classes": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", + "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "requires": { + "babel-helper-define-map": "6.26.0", + "babel-helper-function-name": "6.24.1", + "babel-helper-optimise-call-expression": "6.24.1", + "babel-helper-replace-supers": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-computed-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", + "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-for-of": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", + "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", + "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-amd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", + "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "requires": { + "babel-plugin-transform-es2015-modules-commonjs": "6.26.2", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", + "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", + "requires": { + "babel-plugin-transform-strict-mode": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-systemjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", + "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-umd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", + "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "requires": { + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-object-super": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", + "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "requires": { + "babel-helper-replace-supers": "6.24.1", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "requires": { + "babel-helper-call-delegate": "6.24.1", + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", + "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "regexpu-core": "2.0.0" + } + }, + "babel-plugin-transform-exponentiation-operator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", + "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", + "requires": { + "babel-helper-builder-binary-assignment-operator-visitor": "6.24.1", + "babel-plugin-syntax-exponentiation-operator": "6.13.0", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-regenerator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", + "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "requires": { + "regenerator-transform": "0.10.1" + } + }, + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-uglify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-uglify/-/babel-plugin-uglify-1.0.2.tgz", + "integrity": "sha1-17zasTKvutsL80eaVmbrjeCCYQ8=", + "requires": { + "uglify-js": "2.8.29" + }, + "dependencies": { + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "requires": { + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + } + }, + "yargs": { + "version": "3.10.0", + "resolved": "http://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } + } + } + }, + "babel-polyfill": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", + "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", + "requires": { + "babel-runtime": "6.26.0", + "core-js": "2.5.7", + "regenerator-runtime": "0.10.5" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" + } + } + }, + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "requires": { + "babel-core": "6.26.3", + "babel-runtime": "6.26.0", + "core-js": "2.5.7", + "home-or-tmp": "2.0.0", + "lodash": "4.17.10", + "mkdirp": "0.5.1", + "source-map-support": "0.4.18" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "2.5.7", + "regenerator-runtime": "0.11.1" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "requires": { + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.10" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "requires": { + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.4", + "lodash": "4.17.10" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "requires": { + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.10", + "to-fast-properties": "1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base64-js": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", + "integrity": "sha1-EQHpVE9KdrG8OybUUsqW16NeeXg=" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "before-after-hook": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-1.1.0.tgz", + "integrity": "sha512-VOMDtYPwLbIncTxNoSzRyvaMxtXmLWLUqr8k5AfC1BzLk34HvBXaQX8snOwQZ4c0aX8aSERqtJSiI9/m2u5kuA==" + }, + "binary-extensions": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", + "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=" + }, + "bl": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "requires": { + "readable-stream": "2.3.6", + "safe-buffer": "5.1.2" + } + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "requires": { + "inherits": "2.0.3" + } + }, + "body-parser": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "1.0.4", + "debug": "2.6.9", + "depd": "1.1.2", + "http-errors": "1.6.3", + "iconv-lite": "0.4.19", + "on-finished": "2.3.0", + "qs": "6.5.1", + "raw-body": "2.3.2", + "type-is": "1.6.16" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "requires": { + "expand-range": "1.8.2", + "preserve": "0.2.0", + "repeat-element": "1.1.3" + } + }, + "brfs": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/brfs/-/brfs-1.6.1.tgz", + "integrity": "sha512-OfZpABRQQf+Xsmju8XE9bDjs+uU4vLREGolP7bDgcpsI17QREyZ4Bl+2KLxxx1kCgA0fAIhKQBaBYh+PEcCqYQ==", + "requires": { + "quote-stream": "1.0.2", + "resolve": "1.8.1", + "static-module": "2.2.5", + "through2": "2.0.3" + } + }, + "brotli": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.2.tgz", + "integrity": "sha1-UlqcrU/LqWR119OI9q7LE+7VL0Y=", + "requires": { + "base64-js": "1.3.0" + }, + "dependencies": { + "base64-js": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" + } + } + }, + "browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" + } + } + }, + "browserify-optional": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-optional/-/browserify-optional-1.0.1.tgz", + "integrity": "sha1-HhNyLP3g2F8SFnbCpyztUzoBiGk=", + "requires": { + "ast-transform": "0.0.0", + "ast-types": "0.7.8", + "browser-resolve": "1.11.3" + } + }, + "browserslist": { + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.11.3.tgz", + "integrity": "sha512-yWu5cXT7Av6mVwzWc8lMsJMHWn4xyjSuGYi4IozbVTLUOEYPSagUB8kiMDUHA1fS3zjr8nkxkn9jdvug4BBRmA==", + "requires": { + "caniuse-lite": "1.0.30000885", + "electron-to-chromium": "1.3.63" + } + }, + "btoa-lite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz", + "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=" + }, + "buffer": { + "version": "3.6.0", + "resolved": "http://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz", + "integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=", + "requires": { + "base64-js": "0.0.8", + "ieee754": "1.1.12", + "isarray": "1.0.0" + } + }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "requires": { + "buffer-alloc-unsafe": "1.1.0", + "buffer-fill": "1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, + "buffer-equal": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", + "integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs=" + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "requires": { + "callsites": "0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=" + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "requires": { + "camelcase": "2.1.1", + "map-obj": "1.0.1" + }, + "dependencies": { + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + } + } + }, + "caniuse-lite": { + "version": "1.0.30000885", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000885.tgz", + "integrity": "sha512-cXKbYwpxBLd7qHyej16JazPoUacqoVuDhvR61U7Fr5vSxMUiodzcYa1rQYRYfZ5GexV03vGZHd722vNPLjPJGQ==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "caw": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz", + "integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==", + "requires": { + "get-proxy": "2.1.0", + "isurl": "1.0.0", + "tunnel-agent": "0.6.0", + "url-to-options": "1.0.1" + } + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + } + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "requires": { + "anymatch": "1.3.2", + "async-each": "1.0.1", + "glob-parent": "2.0.0", + "inherits": "2.0.3", + "is-binary-path": "1.0.1", + "is-glob": "2.0.1", + "path-is-absolute": "1.0.1", + "readdirp": "2.1.0" + } + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==" + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "requires": { + "restore-cursor": "2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "columnify": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz", + "integrity": "sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=", + "requires": { + "strip-ansi": "3.0.1", + "wcwidth": "1.0.1" + } + }, + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", + "requires": { + "graceful-readlink": "1.0.1" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "1.1.1", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "typedarray": "0.0.6" + } + }, + "config-chain": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.11.tgz", + "integrity": "sha1-q6CXR9++TD5w52am5BWG4YWfxvI=", + "requires": { + "ini": "1.3.5", + "proto-list": "1.2.4" + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "core-js": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "requires": { + "lru-cache": "4.1.3", + "shebang-command": "1.2.0", + "which": "1.3.1" + } + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "requires": { + "array-find-index": "1.0.2" + } + }, + "d": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "requires": { + "es5-ext": "0.10.46" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "1.0.0" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "decompress": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.0.tgz", + "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", + "requires": { + "decompress-tar": "4.1.1", + "decompress-tarbz2": "4.1.1", + "decompress-targz": "4.1.1", + "decompress-unzip": "4.0.1", + "graceful-fs": "4.1.11", + "make-dir": "1.3.0", + "pify": "2.3.0", + "strip-dirs": "2.1.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "requires": { + "mimic-response": "1.0.1" + } + }, + "decompress-tar": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", + "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", + "requires": { + "file-type": "5.2.0", + "is-stream": "1.1.0", + "tar-stream": "1.6.1" + } + }, + "decompress-tarbz2": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", + "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "requires": { + "decompress-tar": "4.1.1", + "file-type": "6.2.0", + "is-stream": "1.1.0", + "seek-bzip": "1.0.5", + "unbzip2-stream": "1.2.5" + }, + "dependencies": { + "file-type": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", + "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==" + } + } + }, + "decompress-targz": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", + "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", + "requires": { + "decompress-tar": "4.1.1", + "file-type": "5.2.0", + "is-stream": "1.1.0" + } + }, + "decompress-unzip": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", + "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", + "requires": { + "file-type": "3.9.0", + "get-stream": "2.3.1", + "pify": "2.3.0", + "yauzl": "2.10.0" + }, + "dependencies": { + "file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=" + }, + "get-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", + "requires": { + "object-assign": "4.1.1", + "pinkie-promise": "2.0.1" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "requires": { + "clone": "1.0.4" + } + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.1", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "requires": { + "repeating": "2.0.1" + } + }, + "dfa": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.1.0.tgz", + "integrity": "sha1-0wIYvRDQMPpCHfPrvIIoVGOjF4E=", + "requires": { + "babel-runtime": "6.26.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "requires": { + "esutils": "2.0.2" + } + }, + "download": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/download/-/download-6.2.5.tgz", + "integrity": "sha512-DpO9K1sXAST8Cpzb7kmEhogJxymyVUd5qz/vCOSyvwtp2Klj2XcDt5YUuasgxka44SxF0q5RriKIwJmQHG2AuA==", + "requires": { + "caw": "2.0.1", + "content-disposition": "0.5.2", + "decompress": "4.2.0", + "ext-name": "5.0.0", + "file-type": "5.2.0", + "filenamify": "2.1.0", + "get-stream": "3.0.0", + "got": "7.1.0", + "make-dir": "1.3.0", + "p-event": "1.3.0", + "pify": "3.0.0" + } + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "requires": { + "readable-stream": "2.3.6" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "optional": true, + "requires": { + "jsbn": "0.1.1", + "safer-buffer": "2.1.2" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "electron-to-chromium": { + "version": "1.3.63", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.63.tgz", + "integrity": "sha512-Ec35NNY040HKuSxMAzBMgz/uUI78amSWpBUD9x2gN7R7gkb/wgAcClngWklcLP0/lm/g0UUYHnC/tUIlZj8UvQ==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "0.4.24" + } + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "requires": { + "once": "1.4.0" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "0.2.1" + } + }, + "es5-ext": { + "version": "0.10.46", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.46.tgz", + "integrity": "sha512-24XxRvJXNFwEMpJb3nOkiRJKRoupmjYmOPVlI65Qy2SrtxwOTB+g6ODjBKOtwEHbYrhWRty9xxOWLNdClT2djw==", + "requires": { + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1", + "next-tick": "1.0.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.46", + "es6-symbol": "3.1.1" + } + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.46", + "es6-iterator": "2.0.3", + "es6-set": "0.1.5", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } + }, + "es6-promise": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-2.3.0.tgz", + "integrity": "sha1-lu258v2wGZWCKyY92KratnSBgbw=" + }, + "es6-promisify-all": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/es6-promisify-all/-/es6-promisify-all-0.1.0.tgz", + "integrity": "sha1-RCuaHqjgCw/VsodyVVBY/eXp8gc=", + "requires": { + "es6-promisify": "github:pgaubatz/es6-promisify#3d8966c58bace65f762b7335e99e3f43b987bce4" + }, + "dependencies": { + "es6-promisify": { + "version": "github:pgaubatz/es6-promisify#3d8966c58bace65f762b7335e99e3f43b987bce4", + "requires": { + "es6-promise": "2.3.0" + } + } + } + }, + "es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.46", + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } + }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.46" + } + }, + "es6-weak-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.46", + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "escodegen": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.1.tgz", + "integrity": "sha512-6hTjO1NAWkHnDk3OqQ4YrCuwwmGHL9S3nPlzBOUG/R44rda3wLNrfvQ5fkSGjyhHFKM7ALPKcKGrwvCLe0lC7Q==", + "requires": { + "esprima": "3.1.3", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.6.1" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + } + } + }, + "escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", + "requires": { + "es6-map": "0.1.5", + "es6-weak-map": "2.0.2", + "esrecurse": "4.2.1", + "estraverse": "4.2.0" + } + }, + "eslint": { + "version": "4.19.1", + "resolved": "http://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", + "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", + "requires": { + "ajv": "5.5.2", + "babel-code-frame": "6.26.0", + "chalk": "2.4.1", + "concat-stream": "1.6.2", + "cross-spawn": "5.1.0", + "debug": "3.1.0", + "doctrine": "2.1.0", + "eslint-scope": "3.7.3", + "eslint-visitor-keys": "1.0.0", + "espree": "3.5.4", + "esquery": "1.0.1", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.3", + "globals": "11.7.0", + "ignore": "3.3.10", + "imurmurhash": "0.1.4", + "inquirer": "3.3.0", + "is-resolvable": "1.1.0", + "js-yaml": "3.12.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "regexpp": "1.1.0", + "require-uncached": "1.0.3", + "semver": "5.5.1", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.2", + "text-table": "0.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "1.9.3" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" + } + }, + "globals": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", + "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==" + }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "requires": { + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.2.0", + "figures": "2.0.0", + "lodash": "4.17.10", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "eslint-config-qx": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-qx/-/eslint-config-qx-0.1.0.tgz", + "integrity": "sha512-fkQSBji7cwh63SuFoM1byJgO6ZWE2m1C0e8dwxEJy2S5RQrqFAIu7faU0Szi7Cub+bPPKlpVfIv3dfieaaAbYg==", + "requires": { + "eslint": "3.19.0", + "eslint-plugin-qx-rules": "0.1.0" + }, + "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ajv-keywords": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=" + }, + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=" + }, + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "requires": { + "restore-cursor": "1.0.1" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "eslint": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", + "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", + "requires": { + "babel-code-frame": "6.26.0", + "chalk": "1.1.3", + "concat-stream": "1.6.2", + "debug": "2.6.9", + "doctrine": "2.1.0", + "escope": "3.6.0", + "espree": "3.5.4", + "esquery": "1.0.1", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "glob": "7.1.3", + "globals": "9.18.0", + "ignore": "3.3.10", + "imurmurhash": "0.1.4", + "inquirer": "0.12.0", + "is-my-json-valid": "2.19.0", + "is-resolvable": "1.1.0", + "js-yaml": "3.12.0", + "json-stable-stringify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.10", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "1.2.1", + "progress": "1.1.8", + "require-uncached": "1.0.3", + "shelljs": "0.7.8", + "strip-bom": "3.0.0", + "strip-json-comments": "2.0.1", + "table": "3.8.3", + "text-table": "0.2.0", + "user-home": "2.0.0" + } + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "requires": { + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1" + } + }, + "inquirer": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", + "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", + "requires": { + "ansi-escapes": "1.4.0", + "ansi-regex": "2.1.1", + "chalk": "1.1.3", + "cli-cursor": "1.0.2", + "cli-width": "2.2.0", + "figures": "1.7.0", + "lodash": "4.17.10", + "readline2": "1.0.1", + "run-async": "0.1.0", + "rx-lite": "3.1.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "through": "2.3.8" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "onetime": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=" + }, + "pluralize": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", + "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=" + }, + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=" + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "requires": { + "exit-hook": "1.1.1", + "onetime": "1.1.0" + } + }, + "run-async": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", + "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", + "requires": { + "once": "1.4.0" + } + }, + "rx-lite": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", + "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=" + }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=" + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "table": { + "version": "3.8.3", + "resolved": "http://registry.npmjs.org/table/-/table-3.8.3.tgz", + "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", + "requires": { + "ajv": "4.11.8", + "ajv-keywords": "1.5.1", + "chalk": "1.1.3", + "lodash": "4.17.10", + "slice-ansi": "0.0.4", + "string-width": "2.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "3.0.0" + } + } + } + } + } + }, + "eslint-plugin-qx-rules": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-qx-rules/-/eslint-plugin-qx-rules-0.1.0.tgz", + "integrity": "sha512-TmldxfvDvatPOtJxr1lFJsC0dTg3idZ3svQwRoR01zoZW7mJvBWxBGHeITUuH7qw9BcNPdyF4cV1fzUXejBvPg==" + }, + "eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", + "requires": { + "esrecurse": "4.2.1", + "estraverse": "4.2.0" + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==" + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "requires": { + "acorn": "5.7.2", + "acorn-jsx": "3.0.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "requires": { + "estraverse": "4.2.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "requires": { + "estraverse": "4.2.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.46" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + } + }, + "exit-hook": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=" + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "requires": { + "is-posix-bracket": "0.1.1" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "requires": { + "fill-range": "2.2.4" + } + }, + "express": { + "version": "4.16.3", + "resolved": "http://registry.npmjs.org/express/-/express-4.16.3.tgz", + "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", + "requires": { + "accepts": "1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.2", + "content-disposition": "0.5.2", + "content-type": "1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "1.1.2", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "1.1.2", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "2.0.4", + "qs": "6.5.1", + "range-parser": "1.2.0", + "safe-buffer": "5.1.1", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "1.4.0", + "type-is": "1.6.16", + "utils-merge": "1.0.1", + "vary": "1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + } + } + }, + "ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "requires": { + "mime-db": "1.36.0" + } + }, + "ext-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "requires": { + "ext-list": "2.2.2", + "sort-keys-length": "1.0.1" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "external-editor": { + "version": "2.2.0", + "resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "requires": { + "chardet": "0.4.2", + "iconv-lite": "0.4.24", + "tmp": "0.0.33" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "requires": { + "is-extglob": "1.0.0" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "falafel": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/falafel/-/falafel-2.1.0.tgz", + "integrity": "sha1-lrsXdh2rqU9G0AFzizzt86Z/4Gw=", + "requires": { + "acorn": "5.7.2", + "foreach": "2.0.5", + "isarray": "0.0.1", + "object-keys": "1.0.12" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + } + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "requires": { + "pend": "1.2.0" + } + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "requires": { + "flat-cache": "1.3.0", + "object-assign": "4.1.1" + } + }, + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=" + }, + "filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=" + }, + "filenamify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz", + "integrity": "sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==", + "requires": { + "filename-reserved-regex": "2.0.0", + "strip-outer": "1.0.1", + "trim-repeated": "1.0.0" + } + }, + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "3.1.0", + "repeat-element": "1.1.3", + "repeat-string": "1.6.1" + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.4.0", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "flat-cache": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", + "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "requires": { + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } + }, + "follow-redirects": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.0.0.tgz", + "integrity": "sha1-jjQpjL0uF28lTv/sdaHHjMhJ/Tc=", + "requires": { + "debug": "2.6.9" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "fontkit": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-1.7.7.tgz", + "integrity": "sha1-668tjz/t8wKuPGS0vurdwkf827E=", + "requires": { + "babel-runtime": "6.26.0", + "brfs": "1.6.1", + "brotli": "1.3.2", + "browserify-optional": "1.0.1", + "clone": "1.0.4", + "deep-equal": "1.0.1", + "dfa": "1.1.0", + "restructure": "0.5.4", + "tiny-inflate": "1.0.2", + "unicode-properties": "1.1.0", + "unicode-trie": "0.3.1" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "requires": { + "for-in": "1.0.2" + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.6", + "mime-types": "2.1.20" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fstream": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", + "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.2" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "1.2.0", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.3" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + }, + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "requires": { + "globule": "1.2.1" + } + }, + "generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "requires": { + "is-property": "1.0.2" + } + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "requires": { + "is-property": "1.0.2" + } + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" + }, + "get-proxy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz", + "integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==", + "requires": { + "npm-conf": "1.1.3" + } + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "1.0.0" + } + }, + "github-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/github-api/-/github-api-3.0.0.tgz", + "integrity": "sha1-KDL5jQ06g/FIXi2zLJJZ5LnECnU=", + "requires": { + "axios": "0.15.3", + "debug": "2.6.9", + "js-base64": "2.4.9", + "utf8": "2.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "requires": { + "glob-parent": "2.0.0", + "is-glob": "2.0.1" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "requires": { + "is-glob": "2.0.1" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.3", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + }, + "globule": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", + "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", + "requires": { + "glob": "7.1.3", + "lodash": "4.17.10", + "minimatch": "3.0.4" + } + }, + "got": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", + "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", + "requires": { + "decompress-response": "3.3.0", + "duplexer3": "0.1.4", + "get-stream": "3.0.0", + "is-plain-obj": "1.1.0", + "is-retry-allowed": "1.1.0", + "is-stream": "1.1.0", + "isurl": "1.0.0", + "lowercase-keys": "1.0.1", + "p-cancelable": "0.3.0", + "p-timeout": "1.2.1", + "safe-buffer": "5.1.2", + "timed-out": "4.0.1", + "url-parse-lax": "1.0.0", + "url-to-options": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "requires": { + "ajv": "5.5.2", + "har-schema": "2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-color": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", + "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==" + }, + "has-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "requires": { + "has-symbol-support-x": "1.4.2" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": "1.4.0" + } + }, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "requires": { + "agent-base": "4.2.1", + "debug": "3.1.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.14.2" + } + }, + "https-proxy-agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "requires": { + "agent-base": "4.2.1", + "debug": "3.1.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": "2.1.2" + } + }, + "ieee754": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", + "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==" + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" + }, + "image-size": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.6.3.tgz", + "integrity": "sha512-47xSUiQioGaB96nqtp5/q55m0aBQSQdyIloMOc/x+QVTDZLNmXE892IIDrJ0hM1A5vcNUDD5tDffkSP5lCaIIA==" + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "in-publish": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", + "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=" + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "requires": { + "repeating": "2.0.1" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + }, + "inquirer": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-4.0.2.tgz", + "integrity": "sha512-+f3qDNeZpkhFJ61NBA9jXDrGGhoQuqfEum9A681c9oHoIbGgVqjogKynjB/vNVP+nVu9w3FbFQ35c0ibU0MaIQ==", + "requires": { + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.2.0", + "figures": "2.0.0", + "lodash": "4.17.10", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "1.9.3" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=" + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "1.4.0" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "requires": { + "binary-extensions": "1.11.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=" + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "requires": { + "is-primitive": "2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "requires": { + "is-extglob": "1.0.0" + } + }, + "is-my-ip-valid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", + "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==" + }, + "is-my-json-valid": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz", + "integrity": "sha512-mG0f/unGX1HZ5ep4uhRaPOS8EkAY8/j6mDRMJrutq4CqhoJWYp7qAlonIPy3TV7p3ju4TK9fo/PbnoksWmsp5Q==", + "requires": { + "generate-function": "2.3.1", + "generate-object-property": "1.2.0", + "is-my-ip-valid": "1.0.0", + "jsonpointer": "4.0.1", + "xtend": "4.0.1" + } + }, + "is-natural-number": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", + "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=" + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "requires": { + "kind-of": "3.2.2" + } + }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=" + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=" + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "requires": { + "is-path-inside": "1.0.1" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=" + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=" + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" + }, + "is-retry-allowed": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", + "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=" + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "requires": { + "has-to-string-tag-x": "1.4.1", + "is-object": "1.0.1" + } + }, + "js-base64": { + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.9.tgz", + "integrity": "sha512-xcinL3AuDJk7VSzsHgb9DvvIXayBbadtMZ4HFPx8rUszbW1MuNMlwYVC4zzCZ6e1sqZpnNS5ZFYOhXqA39T7LQ==" + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.1" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, + "jsonlint": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.3.tgz", + "integrity": "sha512-jMVTMzP+7gU/IyC6hvKyWpUU8tmTkK5b3BPNuMI9U8Sit+YAWLlZwB6Y6YrdCxfg2kNz05p3XY3Bmm4m26Nv3A==", + "requires": { + "JSV": "4.0.2", + "nomnom": "1.8.1" + } + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "1.1.6" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "requires": { + "invert-kv": "1.0.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "requires": { + "is-utf8": "0.2.1" + } + } + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + } + } + }, + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + }, + "lodash.mergewith": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz", + "integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==" + }, + "lodash.pickby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", + "integrity": "sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=" + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "3.0.2" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "requires": { + "currently-unhandled": "0.4.1", + "signal-exit": "3.0.2" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" + }, + "lru-cache": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", + "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "magic-string": { + "version": "0.22.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", + "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", + "requires": { + "vlq": "0.2.3" + } + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "requires": { + "pify": "3.0.0" + } + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" + }, + "math-random": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", + "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "requires": { + "mimic-fn": "1.2.0" + } + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "requires": { + "camelcase-keys": "2.1.0", + "decamelize": "1.2.0", + "loud-rejection": "1.6.0", + "map-obj": "1.0.1", + "minimist": "1.2.0", + "normalize-package-data": "2.4.0", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "redent": "1.0.0", + "trim-newlines": "1.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + } + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "merge-source-map": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.0.4.tgz", + "integrity": "sha1-pd5GU42uhNQRTMXqArR3KmNGcB8=", + "requires": { + "source-map": "0.5.7" + } + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "requires": { + "arr-diff": "2.0.0", + "array-unique": "0.2.1", + "braces": "1.8.5", + "expand-brackets": "0.1.5", + "extglob": "0.3.2", + "filename-regex": "2.0.1", + "is-extglob": "1.0.0", + "is-glob": "2.0.1", + "kind-of": "3.2.2", + "normalize-path": "2.1.1", + "object.omit": "2.0.1", + "parse-glob": "3.0.4", + "regex-cache": "0.4.4" + } + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" + }, + "mime-types": { + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", + "requires": { + "mime-db": "1.36.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + }, + "nan": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.0.tgz", + "integrity": "sha512-F4miItu2rGnV2ySkXOQoA8FKz/SR2Q2sWP0sbTxNxz/tuokeC8WxOhPMcwi0qIyGtVn/rrSeLbvVkznqCdwYnw==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "0.1.12", + "is-stream": "1.1.0" + } + }, + "node-gyp": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", + "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", + "requires": { + "fstream": "1.0.11", + "glob": "7.1.3", + "graceful-fs": "4.1.11", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "npmlog": "4.1.2", + "osenv": "0.1.5", + "request": "2.87.0", + "rimraf": "2.6.2", + "semver": "5.3.0", + "tar": "2.2.1", + "which": "1.3.1" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" + } + } + }, + "node-sass": { + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.3.tgz", + "integrity": "sha512-XzXyGjO+84wxyH7fV6IwBOTrEBe2f0a6SBze9QWWYR/cL74AcQUks2AsqcCZenl/Fp/JVbuEaLpgrLtocwBUww==", + "requires": { + "async-foreach": "0.1.3", + "chalk": "1.1.3", + "cross-spawn": "3.0.1", + "gaze": "1.1.3", + "get-stdin": "4.0.1", + "glob": "7.1.3", + "in-publish": "2.0.0", + "lodash.assign": "4.2.0", + "lodash.clonedeep": "4.5.0", + "lodash.mergewith": "4.6.1", + "meow": "3.7.0", + "mkdirp": "0.5.1", + "nan": "2.11.0", + "node-gyp": "3.8.0", + "npmlog": "4.1.2", + "request": "2.87.0", + "sass-graph": "2.2.4", + "stdout-stream": "1.4.1", + "true-case-path": "1.0.3" + }, + "dependencies": { + "cross-spawn": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", + "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", + "requires": { + "lru-cache": "4.1.3", + "which": "1.3.1" + } + } + } + }, + "nomnom": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", + "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", + "requires": { + "chalk": "0.4.0", + "underscore": "1.6.0" + }, + "dependencies": { + "ansi-styles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", + "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=" + }, + "chalk": { + "version": "0.4.0", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", + "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", + "requires": { + "ansi-styles": "1.0.0", + "has-color": "0.1.7", + "strip-ansi": "0.1.1" + } + }, + "strip-ansi": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", + "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=" + } + } + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "requires": { + "abbrev": "1.1.1" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "requires": { + "hosted-git-info": "2.7.1", + "is-builtin-module": "1.0.0", + "semver": "5.5.1", + "validate-npm-package-license": "3.0.4" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "1.1.0" + } + }, + "npm-conf": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", + "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", + "requires": { + "config-chain": "1.1.11", + "pify": "3.0.0" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "requires": { + "path-key": "2.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "1.1.5", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-inspect": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.4.1.tgz", + "integrity": "sha512-wqdhLpfCUbEsoEwl3FXwGyv8ief1k/1aUdIPCqVnupM6e8l63BEJdiF/0swtn04/8p05tG/T0FrpTlfwvljOdw==" + }, + "object-keys": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", + "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==" + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "requires": { + "for-own": "0.1.5", + "is-extendable": "0.1.1" + } + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "requires": { + "mimic-fn": "1.2.0" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + }, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + } + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-locale": { + "version": "1.4.0", + "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "requires": { + "lcid": "1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "p-cancelable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", + "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==" + }, + "p-event": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-1.3.0.tgz", + "integrity": "sha1-jmtPT2XHK8W2/ii3XtqHT5akoIU=", + "requires": { + "p-timeout": "1.2.1" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "1.3.0" + } + }, + "p-timeout": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", + "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", + "requires": { + "p-finally": "1.0.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + }, + "pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "requires": { + "glob-base": "0.3.0", + "is-dotfile": "1.0.3", + "is-extglob": "1.0.0", + "is-glob": "2.0.1" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "1.3.2" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "2.0.4" + } + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==" + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, + "progress": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", + "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=" + }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "requires": { + "forwarded": "0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "qooxdoo": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/qooxdoo/-/qooxdoo-5.0.1.tgz", + "integrity": "sha1-BHZB07B5wahcBpNun5uqoraP8mI=" + }, + "qooxdoo-sdk": { + "version": "6.0.0-alpha-20180826", + "resolved": "https://registry.npmjs.org/qooxdoo-sdk/-/qooxdoo-sdk-6.0.0-alpha-20180826.tgz", + "integrity": "sha512-RsAwEKRXwm50qXpEtzUD5pCrGrenakDLCEC9kG+m4/XhB3xRr5744X7U9QQdG27BsPJtO1dLBoYI2YWtYIuhGg==" + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "quote-stream": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/quote-stream/-/quote-stream-1.0.2.tgz", + "integrity": "sha1-hJY/jJwmuULhU/7rU6rnRlK34LI=", + "requires": { + "buffer-equal": "0.0.1", + "minimist": "1.2.0", + "through2": "2.0.3" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + } + } + }, + "qxcompiler": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/qxcompiler/-/qxcompiler-0.2.14.tgz", + "integrity": "sha512-Ohn4iCmOodj0UdVFKVO1dGKPmsJMnV6Bcv7ph1qoloLIT4tGlC+vsnFvf/sKJyShgWKUD5cKQdTAUpWCBn0ZIw==", + "requires": { + "@octokit/rest": "15.11.1", + "@qooxdoo/preset-env": "1.0.0", + "app-module-path": "2.2.0", + "async": "2.6.1", + "async-each": "1.0.1", + "babel-core": "6.26.3", + "babel-eslint": "6.1.2", + "babel-generator": "6.26.1", + "babel-plugin-transform-es2015-block-scoping": "6.15.0", + "babel-plugin-uglify": "1.0.2", + "babel-polyfill": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "chokidar": "1.7.0", + "columnify": "1.5.4", + "download": "6.2.5", + "es6-promisify-all": "0.1.0", + "eslint": "4.19.1", + "eslint-config-qx": "0.1.0", + "eslint-plugin-qx-rules": "0.1.0", + "express": "4.16.3", + "flat-cache": "1.3.0", + "fontkit": "1.7.7", + "gauge": "2.7.4", + "github-api": "3.0.0", + "glob": "7.1.3", + "image-size": "0.6.3", + "inquirer": "4.0.2", + "json-to-ast": "git+https://github.com/johnspackman/json-to-ast.git#a42fbe89a4f2033062213c49bfec7cf429d94db6", + "jsonlint": "1.6.3", + "node-fetch": "1.7.3", + "node-sass": "4.9.3", + "qooxdoo": "5.0.1", + "qooxdoo-sdk": "6.0.0-alpha-20180826", + "rimraf": "2.6.2", + "semver": "5.5.1", + "tmp": "0.0.33", + "uglify-js": "3.4.9", + "upath": "1.1.0", + "xml2js": "0.4.19", + "yargs": "8.0.2" + }, + "dependencies": { + "json-to-ast": { + "version": "git+https://github.com/johnspackman/json-to-ast.git#a42fbe89a4f2033062213c49bfec7cf429d94db6" + } + } + }, + "randomatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.0.tgz", + "integrity": "sha512-KnGPVE0lo2WoXxIZ7cPR8YBpiol4gsSuOwDSg410oHh80ZMp5EiypNqL2K4Z77vJn6lB5rap7IkAmcUlalcnBQ==", + "requires": { + "is-number": "4.0.0", + "kind-of": "6.0.2", + "math-random": "1.0.1" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + }, + "dependencies": { + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" + }, + "http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": "1.4.0" + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + } + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" + } + }, + "readdirp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", + "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "requires": { + "graceful-fs": "4.1.11", + "minimatch": "3.0.4", + "readable-stream": "2.3.6", + "set-immediate-shim": "1.0.1" + } + }, + "readline2": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", + "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "mute-stream": "0.0.5" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "mute-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", + "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=" + } + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "requires": { + "resolve": "1.8.1" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "requires": { + "indent-string": "2.1.0", + "strip-indent": "1.0.1" + } + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==" + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "regenerator-transform": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "private": "0.1.8" + } + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "requires": { + "is-equal-shallow": "0.1.3" + } + }, + "regexpp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==" + }, + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "requires": { + "regenerate": "1.4.0", + "regjsgen": "0.2.0", + "regjsparser": "0.1.5" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "requires": { + "jsesc": "0.5.0" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "requires": { + "is-finite": "1.0.2" + } + }, + "request": { + "version": "2.87.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", + "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.8.0", + "caseless": "0.12.0", + "combined-stream": "1.0.6", + "extend": "3.0.2", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.0.3", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.20", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.2", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", + "uuid": "3.3.2" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + } + }, + "resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "requires": { + "path-parse": "1.0.6" + } + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=" + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + } + }, + "restructure": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/restructure/-/restructure-0.5.4.tgz", + "integrity": "sha1-9U591WNZD7NP1r9Vh2EJrsyyjeg=", + "requires": { + "browserify-optional": "1.0.1" + } + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "requires": { + "align-text": "0.1.4" + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "requires": { + "glob": "7.1.3" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "requires": { + "is-promise": "2.1.0" + } + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=" + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "requires": { + "rx-lite": "4.0.8" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sass-graph": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", + "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=", + "requires": { + "glob": "7.1.3", + "lodash": "4.17.10", + "scss-tokenizer": "0.2.3", + "yargs": "7.1.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "yargs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", + "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", + "requires": { + "camelcase": "3.0.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.3", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "y18n": "3.2.1", + "yargs-parser": "5.0.0" + } + } + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "scss-tokenizer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", + "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "requires": { + "js-base64": "2.4.9", + "source-map": "0.4.4" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "seek-bzip": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", + "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", + "requires": { + "commander": "2.8.1" + } + }, + "semver": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==" + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "requires": { + "debug": "2.6.9", + "depd": "1.1.2", + "destroy": "1.0.4", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "fresh": "0.5.2", + "http-errors": "1.6.3", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "2.3.0", + "range-parser": "1.2.0", + "statuses": "1.4.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "requires": { + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "parseurl": "1.3.2", + "send": "0.16.2" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=" + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "shallow-copy": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", + "integrity": "sha1-QV9CcC1z2BAzApLMXuhurhoRoXA=" + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "shelljs": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", + "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", + "requires": { + "glob": "7.1.3", + "interpret": "1.1.0", + "rechoir": "0.6.2" + } + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "requires": { + "is-fullwidth-code-point": "2.0.0" + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "requires": { + "is-plain-obj": "1.1.0" + } + }, + "sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=", + "requires": { + "sort-keys": "1.1.2" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "requires": { + "source-map": "0.5.7" + } + }, + "spdx-correct": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", + "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "requires": { + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", + "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==" + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "requires": { + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", + "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==" + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "sshpk": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", + "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", + "requires": { + "asn1": "0.2.4", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.2", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.2", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "safer-buffer": "2.1.2", + "tweetnacl": "0.14.5" + } + }, + "static-eval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.0.tgz", + "integrity": "sha512-6flshd3F1Gwm+Ksxq463LtFd1liC77N/PX1FVVc3OzL3hAmo2fwHFbuArkcfi7s9rTNsLEhcRmXGFZhlgy40uw==", + "requires": { + "escodegen": "1.9.1" + } + }, + "static-module": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/static-module/-/static-module-2.2.5.tgz", + "integrity": "sha512-D8vv82E/Kpmz3TXHKG8PPsCPg+RAX6cbCOyvjM6x04qZtQ47EtJFVwRsdov3n5d6/6ynrOY9XB4JkaZwB2xoRQ==", + "requires": { + "concat-stream": "1.6.2", + "convert-source-map": "1.6.0", + "duplexer2": "0.1.4", + "escodegen": "1.9.1", + "falafel": "2.1.0", + "has": "1.0.3", + "magic-string": "0.22.5", + "merge-source-map": "1.0.4", + "object-inspect": "1.4.1", + "quote-stream": "1.0.2", + "readable-stream": "2.3.6", + "shallow-copy": "0.0.1", + "static-eval": "2.0.0", + "through2": "2.0.3" + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + }, + "stdout-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", + "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", + "requires": { + "readable-stream": "2.3.6" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "3.0.0" + } + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" + }, + "strip-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", + "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", + "requires": { + "is-natural-number": "4.0.1" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "requires": { + "get-stdin": "4.0.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "requires": { + "ajv": "5.5.2", + "ajv-keywords": "2.1.1", + "chalk": "2.4.1", + "lodash": "4.17.10", + "slice-ansi": "1.0.0", + "string-width": "2.1.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "1.9.3" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "tar": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "tar-stream": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.1.tgz", + "integrity": "sha512-IFLM5wp3QrJODQFPm6/to3LJZrONdBY/otxcvDIQzu217zKye6yVR3hhi9lAjrC2Z+m/j5oDxMPb1qcd8cIvpA==", + "requires": { + "bl": "1.2.2", + "buffer-alloc": "1.2.0", + "end-of-stream": "1.4.1", + "fs-constants": "1.0.0", + "readable-stream": "2.3.6", + "to-buffer": "1.1.1", + "xtend": "4.0.1" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "requires": { + "readable-stream": "2.3.6", + "xtend": "4.0.1" + } + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" + }, + "tiny-inflate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.2.tgz", + "integrity": "sha1-k9nez/yIBb1X6uQxDwt0Xptvs6c=" + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "1.0.2" + } + }, + "to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" + }, + "tough-cookie": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "requires": { + "punycode": "1.4.1" + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" + }, + "trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" + }, + "true-case-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", + "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", + "requires": { + "glob": "7.1.3" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "1.1.2" + } + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.1.20" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "uglify-js": { + "version": "3.4.9", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", + "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", + "requires": { + "commander": "2.17.1", + "source-map": "0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "optional": true + }, + "unbzip2-stream": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz", + "integrity": "sha512-izD3jxT8xkzwtXRUZjtmRwKnZoeECrfZ8ra/ketwOcusbZEp4mjULMnJOCfTDZBgGQAAY1AJ/IgxcwkavcX9Og==", + "requires": { + "buffer": "3.6.0", + "through": "2.3.8" + } + }, + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=" + }, + "unicode-properties": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.1.0.tgz", + "integrity": "sha1-epbu9J91aC6mnSMV7smsQ//fAME=", + "requires": { + "brfs": "1.6.1", + "unicode-trie": "0.3.1" + } + }, + "unicode-trie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-0.3.1.tgz", + "integrity": "sha1-1nHd3YkQGgi6w3tqUWEBBgIFIIU=", + "requires": { + "pako": "0.2.9", + "tiny-inflate": "1.0.2" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "upath": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", + "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==" + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "requires": { + "prepend-http": "1.0.4" + } + }, + "url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" + }, + "url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=" + }, + "user-home": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", + "requires": { + "os-homedir": "1.0.2" + } + }, + "utf8": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz", + "integrity": "sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "requires": { + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + } + }, + "vlq": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", + "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==" + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "requires": { + "defaults": "1.0.3" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "2.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "2.1.1" + } + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "requires": { + "mkdirp": "0.5.1" + } + }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "requires": { + "sax": "1.2.4", + "xmlbuilder": "9.0.7" + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "yargs": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", + "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", + "requires": { + "camelcase": "4.1.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.3", + "os-locale": "2.1.0", + "read-pkg-up": "2.0.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "7.0.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "2.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "requires": { + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "requires": { + "pify": "2.3.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "yargs-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", + "requires": { + "camelcase": "4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", + "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", + "requires": { + "camelcase": "3.0.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" + } + } + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "requires": { + "buffer-crc32": "0.2.13", + "fd-slicer": "1.1.0" + } + } + } +} diff --git a/services/web/client/source/class/qxapp/Application.js b/services/web/client/source/class/qxapp/Application.js index 26ab5f0ab35..5c3c21b88d6 100644 --- a/services/web/client/source/class/qxapp/Application.js +++ b/services/web/client/source/class/qxapp/Application.js @@ -118,11 +118,20 @@ qx.Class.define("qxapp.Application", { let data = e.getTarget().getResponse(); try { let ajv = new qxapp.wrappers.Ajv(data); - let map = qxapp.data.Store.getInstance().getServices(); + let map = qxapp.data.Store.getInstance().getFakeServices(); for (let key in map) { let check = ajv.validate(map[key]); console.log("services validation result " + key + ":", check); } + /* + let servicesPromise = new qx.Promise(qxapp.data.Store.getInstance().getServices, this); + servicesPromise.then(function(map) { + for (let key in map) { + let check = ajv.validate(map[key]); + console.log("services validation result " + key + ":", check); + } + }); + */ } catch (err) { console.error(err); } diff --git a/services/web/client/source/class/qxapp/components/form/Auto.js b/services/web/client/source/class/qxapp/component/form/Auto.js similarity index 91% rename from services/web/client/source/class/qxapp/components/form/Auto.js rename to services/web/client/source/class/qxapp/component/form/Auto.js index 1d305541da3..675d1288bec 100644 --- a/services/web/client/source/class/qxapp/components/form/Auto.js +++ b/services/web/client/source/class/qxapp/component/form/Auto.js @@ -59,7 +59,7 @@ /* eslint no-warning-comments: "off" */ -qx.Class.define("qxapp.components.form.Auto", { +qx.Class.define("qxapp.component.form.Auto", { extend : qx.ui.form.Form, include : [qx.locale.MTranslation], @@ -69,6 +69,7 @@ qx.Class.define("qxapp.components.form.Auto", { construct : function(content) { this.base(arguments); this.__ctrlMap = {}; + this.__ctrlLinkMap = {}; let formCtrl = this.__formCtrl = new qx.data.controller.Form(null, this); this.__boxCtrl = {}; this.__typeMap = {}; @@ -77,7 +78,7 @@ qx.Class.define("qxapp.components.form.Auto", { } let model = this.__model = formCtrl.createModel(true); - model.addListener("changeBubble", function(e) { + model.addListener("changeBubble", e => { if (!this.__settingData) { this.fireDataEvent("changeData", this.getData()); } @@ -90,12 +91,15 @@ qx.Class.define("qxapp.components.form.Auto", { * fire when the form changes content and * and provide access to the data */ - "changeData" : "qx.event.type.Data" + "changeData" : "qx.event.type.Data", + "linkAdded" : "qx.event.type.Data", + "linkRemoved" : "qx.event.type.Data" }, members : { __boxCtrl : null, __ctrlMap : null, + __ctrlLinkMap : null, __formCtrl: null, __model : null, __settingData : false, @@ -131,6 +135,10 @@ qx.Class.define("qxapp.components.form.Auto", { return this.__ctrlMap[key]; }, + getControlLink : function(key) { + return this.__ctrlLinkMap[key]; + }, + /** * fetch the data for this form @@ -190,7 +198,7 @@ qx.Class.define("qxapp.components.form.Auto", { for (let key in data) { if (typeof data[key] == "object" && data[key].nodeUuid) { - this.getControl(key).setEnabled(false); + this.addLink(key, data[key].nodeUuid, data[key].output); continue; } this.getControl(key).setEnabled(true); @@ -504,10 +512,36 @@ qx.Class.define("qxapp.components.form.Auto", { if (s.set.label) { s.set.label = this["tr"](s.set.label); } - console.log(s.set); control.set(s.set); } + control.key = key; this.__ctrlMap[key] = control; + + let controlLink = new qx.ui.form.TextField().set({ + enabled: false + }); + controlLink.key = key; + this.__ctrlLinkMap[key] = controlLink; + }, + + addLink: function(toPortId, fromNodeId, fromPortId) { + this.getControl(toPortId).setEnabled(false); + this.getControl(toPortId).link = { + nodeUuid: fromNodeId, + output: fromPortId + }; + this.getControlLink(toPortId).setValue("Linked to " + fromNodeId + ": " + fromPortId); + + this.fireDataEvent("linkAdded", toPortId); + }, + + removeLink: function(toPortId) { + this.getControl(toPortId).setEnabled(true); + if ("link" in this.getControl(toPortId)) { + delete this.getControl(toPortId).link; + } + + this.fireDataEvent("linkRemoved", toPortId); } } }); diff --git a/services/web/client/source/class/qxapp/component/form/renderer/PropForm.js b/services/web/client/source/class/qxapp/component/form/renderer/PropForm.js new file mode 100644 index 00000000000..3eeb7f58106 --- /dev/null +++ b/services/web/client/source/class/qxapp/component/form/renderer/PropForm.js @@ -0,0 +1,153 @@ +/* ************************************************************************ + Copyright: 2013 OETIKER+PARTNER AG + 2018 ITIS Foundation + License: MIT + Authors: Tobi Oetiker + Utf8Check: äöü +************************************************************************ */ + +/** + * A special renderer for AutoForms which includes notes below the section header + * widget and next to the individual form widgets. + */ + +/* eslint no-underscore-dangle: ["error", { "allowAfterThis": true, "allow": ["__ctrlMap"] }] */ + +qx.Class.define("qxapp.component.form.renderer.PropForm", { + extend : qx.ui.form.renderer.Single, + /** + * create a page for the View Tab with the given title + * + * @param vizWidget {Widget} visualization widget to embedd + */ + construct: function(form) { + this.base(arguments, form); + let fl = this._getLayout(); + // have plenty of space for input, not for the labels + fl.setColumnFlex(0, 0); + fl.setColumnAlign(0, "left", "top"); + fl.setColumnFlex(1, 1); + fl.setColumnMinWidth(1, 130); + }, + + events: { + "PortDragOver": "qx.event.type.Data", + "PortDrop": "qx.event.type.Data", + "RemoveLink" : "qx.event.type.Data" + }, + + members: { + addItems: function(items, names, title, itemOptions, headerOptions) { + // add the header + if (title !== null) { + this._add( + this._createHeader(title), { + row: this._row, + column: 0, + colSpan: 3 + } + ); + this._row++; + } + + // add the items + for (let i = 0; i < items.length; i++) { + let item = items[i]; + let label = this._createLabel(names[i], item); + this._add(label, { + row: this._row, + column: 0 + }); + label.setBuddy(item); + this._add(item, { + row: this._row, + column: 1 + }); + this._row++; + this._connectVisibility(item, label); + // store the names for translation + if (qx.core.Environment.get("qx.dynlocale")) { + this._names.push({ + name: names[i], + label: label, + item: items[i] + }); + } + label.setDroppable(true); + item.setDroppable(true); + this.__createUIPortConnections(label, item.key); + this.__createUIPortConnections(item, item.key); + } + }, + + getValues: function() { + let data = this._form.getData(); + for (const portId in data) { + let ctrl = this._form.getControl(portId); + if (ctrl && Object.prototype.hasOwnProperty.call(ctrl, "link")) { + data[portId] = ctrl.link; + } + } + return data; + }, + + linkAdded: function(portId) { + let children = this._getChildren(); + for (let i=0; i { + uiElement.addListener(eventPair[0], e => { + const eData = { + event: e, + // nodeId: nodeId, + portId: portId + }; + this.fireDataEvent(eventPair[1], eData); + }, this); + }, this); + } + } +}); diff --git a/services/web/client/source/class/qxapp/component/widget/CollapsableVBox.js b/services/web/client/source/class/qxapp/component/widget/CollapsableVBox.js new file mode 100644 index 00000000000..706f2ee0784 --- /dev/null +++ b/services/web/client/source/class/qxapp/component/widget/CollapsableVBox.js @@ -0,0 +1,127 @@ +qx.Class.define("qxapp.component.widget.CollapsableVBox", { + extend: qx.ui.core.Widget, + + construct: function(headerText = "Header", contentWidgets = []) { + this.base(arguments); + + let widgetLayout = new qx.ui.layout.VBox(5); + this._setLayout(widgetLayout); + + // header + { + let header = this.__headerBox = new qx.ui.container.Composite(new qx.ui.layout.HBox(5).set({ + alignY: "middle" + })); + this._add(header); + + const icon = "@FontAwesome5Solid/expand-arrows-alt/24"; + let expandBtn = this.__expandBtn = new qx.ui.form.Button().set({ + icon: icon, + allowGrowX: false, + allowGrowY: false, + maxWidth: 24, + maxHeight: 24, + padding: 0 + }); + expandBtn.addListener("execute", e => { + this.toggleCollapsed(); + }, this); + } + + // content + { + let content = this.__contentBox = new qx.ui.container.Composite(new qx.ui.layout.VBox(5)); + this._add(content, { + flex: 1 + }); + + this.setContentWidgets(contentWidgets); + } + + this.setHeaderText(headerText); + this.setCollapsed(false); + }, + + properties: { + collapsed: { + nullable: false, + check: "Boolean", + init: false, + apply: "__buildLayout" + }, + headerText: { + check: "String", + init: "", + apply: "__applyHeaderText" + } + }, + + events: {}, + + members: { + __headerBox: null, + __contentBox: null, + __expandBtn: null, + __headerLabel: null, + __contentWidgets: null, + + __buildLayout: function(collapse) { + // header + this.__headerBox.removeAll(); + this.__headerBox.add(this.__expandBtn); + this.__headerBox.add(new qx.ui.core.Spacer(), { + flex: 1 + }); + this.__headerBox.add(this.__headerLabel); + this.__headerBox.add(new qx.ui.core.Spacer(), { + flex: 3 + }); + + // content + this.__contentBox.removeAll(); + if (collapse) { + this.__contentBox.setVisibility("excluded"); + } else { + this.__contentBox.setVisibility("visible"); + for (let i = 0; i < this.__contentWidgets.length; i++) { + let widget = this.__contentWidgets[i].widget; + let map = this.__contentWidgets[i].map; + this.__contentBox.add(widget, map); + } + // this.setWidth(this.getMaxWidth()); + } + }, + + rebuildLayout: function() { + this.__buildLayout(this.getCollapsed()); + }, + + __applyHeaderText: function(newHeader) { + if (this.__headerLabel === null) { + this.__headerLabel = new qx.ui.basic.Label(newHeader).set({ + textAlign: "center" + }); + } + this.__headerLabel.setValue(newHeader); + this.rebuildLayout(); + }, + + setContentWidgets: function(widgets) { + if (Array.isArray(widgets) != true) { + // Type check: Make sure it is a valid array + throw new Error("Invalid type: Need a valid array"); + } + + this.__contentWidgets = widgets; + }, + + addContentWidget: function(widget, map) { + this.__contentWidgets.push({ + widget: widget, + map: map + }); + + this.rebuildLayout(); + } + } +}); diff --git a/services/web/client/source/class/qxapp/component/widget/FileManager.js b/services/web/client/source/class/qxapp/component/widget/FileManager.js new file mode 100644 index 00000000000..afc987e224d --- /dev/null +++ b/services/web/client/source/class/qxapp/component/widget/FileManager.js @@ -0,0 +1,319 @@ +qx.Class.define("qxapp.component.widget.FileManager", { + extend: qx.ui.core.Widget, + + construct: function(nodeModel) { + this.base(arguments); + + this.set({ + nodeModel: nodeModel + }); + + let fileManagerLayout = new qx.ui.layout.VBox(10); + this._setLayout(fileManagerLayout); + + let treesLayout = this._createChildControlImpl("treesLayout"); + + let nodeTree = this.__nodeTree = this._createChildControlImpl("nodeTree"); + treesLayout.add(nodeTree, { + flex: 1 + }); + nodeTree.addListener("changeSelection", this.__itemSelected, this); + + let userTree = this.__userTree = this._createChildControlImpl("userTree"); + treesLayout.add(userTree, { + flex: 1 + }); + userTree.addListener("changeSelection", this.__itemSelected, this); + + let selectedFileLayout = this._createChildControlImpl("selectedFileLayout"); + { + let selectedLabel = this.__selectedLabel = new qx.ui.basic.Label().set({ + decorator: "main", + backgroundColor: "white", + minWidth: 300, + height: 24 + }); + + let downloadBtn = new qx.ui.form.Button().set({ + icon: "@FontAwesome5Solid/cloud-download-alt/24" + }); + downloadBtn.addListener("execute", e => { + this.__downloadFile(); + }, this); + + let deleteBtn = new qx.ui.form.Button().set({ + icon: "@FontAwesome5Solid/trash-alt/24" + }); + deleteBtn.addListener("execute", e => { + this.__deleteFile(); + }, this); + + selectedFileLayout.add(selectedLabel, { + flex: 1 + }); + selectedFileLayout.add(downloadBtn); + selectedFileLayout.add(deleteBtn); + } + + let closeBtn = this.__closeBtn = this._createChildControlImpl("closeButton"); + closeBtn.setEnabled(false); + closeBtn.addListener("execute", function() { + console.log("close"); + }, this); + + this.__reloadNodeTree(); + this.__reloadUserTree(); + }, + + properties: { + nodeModel: { + check: "qxapp.data.model.NodeModel" + } + }, + + members: { + __nodeTree: null, + __userTree: null, + __currentUserId: "ODEI-UUID", + __selectedLabel: null, + __selection: null, + __closeBtn: null, + + _createChildControlImpl: function(id) { + let control; + switch (id) { + case "treesLayout": + control = new qx.ui.container.Composite(new qx.ui.layout.HBox(10)); + this._add(control, { + flex: 1 + }); + break; + case "nodeTree": + case "userTree": + control = new qx.ui.tree.Tree(); + break; + case "selectedFileLayout": + control = new qx.ui.container.Composite(new qx.ui.layout.HBox(5)).set({ + alignY: "middle" + }); + this._add(control); + break; + case "closeButton": + control = new qx.ui.form.Button(this.tr("Close")); + this._add(control); + break; + } + + return control || this.base(arguments, id); + }, + + __reloadNodeTree: function() { + this.__nodeTree.resetRoot(); + + const nodeName = this.getNodeModel().getLabel(); + let root = this.__configureTreeItem(new qx.ui.tree.TreeFolder(), nodeName); + root.setOpen(true); + this.__nodeTree.setRoot(root); + + // this.__populateNodeFiles(); + this.__populateFiles(this.__nodeTree, true, false); + }, + + __reloadUserTree: function() { + this.__userTree.resetRoot(); + + let root = this.__configureTreeItem(new qx.ui.tree.TreeFolder(), this.__currentUserId); + root.setOpen(true); + this.__userTree.setRoot(root); + + // this.__populateUserFiles(); + this.__populateFiles(this.__userTree, false, true); + }, + + __populateFiles: function(tree, isDraggable = false, isDroppable = false) { + const slotName = "listObjects"; + let socket = qxapp.wrappers.WebSocket.getInstance(); + socket.removeSlot(slotName); + socket.on(slotName, function(data) { + for (let i=0; i { + if (e.getOriginalTarget().isDir == true) { + e.preventDefault(); + } else { + // Register supported actions + e.addAction("copy"); + // Register supported types + e.addType("osparc-filePath"); + } + }, this); + }, + + __createDropMechanism: function(treeItem) { + treeItem.setDroppable(true); + treeItem.addListener("dragover", e => { + let compatible = false; + if (e.supportsType("osparc-filePath")) { + const from = e.getRelatedTarget(); + const to = e.getCurrentTarget(); + if (from.isDir === false && to.isDir === true) { + compatible = true; + } + } + if (!compatible) { + e.preventDefault(); + } + }, this); + + treeItem.addListener("drop", e => { + if (e.supportsType("osparc-filePath")) { + const from = e.getRelatedTarget(); + const to = e.getCurrentTarget(); + console.log("Copy", from.path, "to", to.path); + } + }, this); + }, + + __itemSelected: function() { + let selectedItem = this.__nodeTree.getSelection(); + if (selectedItem.length < 1) { + return; + } + if ("path" in selectedItem[0]) { + const data = { + itemPath: selectedItem[0].path, + isDirectory: selectedItem[0].isDir + }; + this.__selection = data.itemPath; + this.__selectedLabel.setValue(data.itemPath); + } + }, + + __downloadFile: function() { + console.log("Download ", this.__selection); + }, + + __deleteFile: function() { + console.log("Delete ", this.__selection); + } + } +}); diff --git a/services/web/client/source/class/qxapp/components/widgets/FileManager.js b/services/web/client/source/class/qxapp/component/widget/FilePicker.js similarity index 83% rename from services/web/client/source/class/qxapp/components/widgets/FileManager.js rename to services/web/client/source/class/qxapp/component/widget/FilePicker.js index 1bc7a398753..771e77dd79b 100644 --- a/services/web/client/source/class/qxapp/components/widgets/FileManager.js +++ b/services/web/client/source/class/qxapp/component/widget/FilePicker.js @@ -1,12 +1,12 @@ /* global XMLHttpRequest */ -qx.Class.define("qxapp.components.widgets.FileManager", { +qx.Class.define("qxapp.component.widget.FilePicker", { extend: qx.ui.core.Widget, - construct: function() { + construct: function(node) { this.base(arguments); - let fileManagerLayout = new qx.ui.layout.VBox(10); - this._setLayout(fileManagerLayout); + let filePickerLayout = new qx.ui.layout.VBox(10); + this._setLayout(filePickerLayout); // Create a button let input = new qx.html.Input("file", { @@ -20,11 +20,11 @@ qx.Class.define("qxapp.components.widgets.FileManager", { let pick = this._createChildControlImpl("addButton"); // Add an event listener - pick.addListener("execute", function(e) { + pick.addListener("execute", e => { input.getDomElement().click(); }); - input.addListener("change", function(e) { + input.addListener("change", e => { let files = input.getDomElement().files; for (let i=0; i { if (e.lengthComputable) { const percentComplete = e.loaded / e.total * 100; progressBar.setValue(percentComplete); diff --git a/services/web/client/source/class/qxapp/component/widget/NodeExposed.js b/services/web/client/source/class/qxapp/component/widget/NodeExposed.js new file mode 100644 index 00000000000..8ade3c00c22 --- /dev/null +++ b/services/web/client/source/class/qxapp/component/widget/NodeExposed.js @@ -0,0 +1,106 @@ +qx.Class.define("qxapp.component.widget.NodeExposed", { + extend: qx.ui.core.Widget, + + construct: function(nodeModel) { + this.base(); + + let nodeExposedLayout = new qx.ui.layout.VBox(10); + this._setLayout(nodeExposedLayout); + + this.set({ + decorator: "main" + }); + + let atom = new qx.ui.basic.Atom().set({ + label: nodeModel.getLabel() + "'s outputs", + center : true, + draggable: true, + droppable: true + }); + + this._add(atom, { + flex: 1 + }); + + this.setNodeModel(nodeModel); + }, + + properties: { + nodeModel: { + check: "qxapp.data.model.NodeModel", + nullable: false + } + }, + + events: { + "LinkDragStart": "qx.event.type.Data", + "LinkDragOver": "qx.event.type.Data", + "LinkDrop": "qx.event.type.Data", + "LinkDragEnd": "qx.event.type.Data" + }, + + members: { + __inputPort: null, + __outputPort: null, + + getNodeId: function() { + return this.getNodeModel().getNodeId(); + }, + + getMetaData: function() { + return this.getNodeModel().getMetaData(); + }, + + populateNodeLayout: function() { + const metaData = this.getNodeModel().getMetaData(); + this.__inputPort = {}; + this.__outputPort = {}; + this.__createUIPorts(true, metaData.inputs); + // this.__createUIPorts(false, metaData.outputs); + }, + + getInputPort: function() { + return this.__inputPort["Input"]; + }, + + getOutputPort: function() { + return this.__outputPort["Output"]; + }, + + __createUIPorts: function(isInput, ports) { + // Always create ports if node is a container + if (!this.getNodeModel().isContainer() && Object.keys(ports).length < 1) { + return; + } + this.__createUIPortConnections(this, isInput); + let label = { + isInput: isInput, + ui: this + }; + label.ui.isInput = isInput; + if (isInput) { + this.__inputPort["Input"] = label; + } else { + this.__outputPort["Output"] = label; + } + }, + + __createUIPortConnections: function(uiPort, isInput) { + [ + ["dragstart", "LinkDragStart"], + ["dragover", "LinkDragOver"], + ["drop", "LinkDrop"], + ["dragend", "LinkDragEnd"] + ].forEach(eventPair => { + uiPort.addListener(eventPair[0], e => { + const eData = { + event: e, + nodeId: this.getNodeId(), + isInput: isInput + }; + this.fireDataEvent(eventPair[1], eData); + }, this); + }, this); + } + } +}); diff --git a/services/web/client/source/class/qxapp/component/widget/NodeInput.js b/services/web/client/source/class/qxapp/component/widget/NodeInput.js new file mode 100644 index 00000000000..ae212b29154 --- /dev/null +++ b/services/web/client/source/class/qxapp/component/widget/NodeInput.js @@ -0,0 +1,138 @@ +qx.Class.define("qxapp.component.widget.NodeInput", { + extend: qx.ui.core.Widget, + + construct: function(nodeModel) { + this.base(); + + let nodeInputLayout = new qx.ui.layout.VBox(10); + this._setLayout(nodeInputLayout); + + this.set({ + decorator: "main" + }); + + let atom = new qx.ui.basic.Atom().set({ + label: nodeModel.getLabel(), + center : true, + draggable: true, + droppable: true + }); + + this._add(atom, { + flex: 1 + }); + + this.setNodeModel(nodeModel); + }, + + properties: { + nodeModel: { + check: "qxapp.data.model.NodeModel", + nullable: false + } + }, + + events: { + "LinkDragStart": "qx.event.type.Data", + "LinkDragOver": "qx.event.type.Data", + "LinkDrop": "qx.event.type.Data", + "LinkDragEnd": "qx.event.type.Data" + }, + + members: { + __inputPort: null, + __outputPort: null, + + getNodeId: function() { + return this.getNodeModel().getNodeId(); + }, + + getMetaData: function() { + return this.getNodeModel().getMetaData(); + }, + + populateNodeLayout: function() { + const metaData = this.getNodeModel().getMetaData(); + this.__inputPort = {}; + this.__outputPort = {}; + // this.__createUIPorts(true, metaData.inputs); + this.__createUIPorts(false, metaData.outputs); + }, + + getInputPort: function() { + return this.__inputPort["Input"]; + }, + + getOutputPort: function() { + return this.__outputPort["Output"]; + }, + + __createUIPorts: function(isInput, ports) { + // Always create ports if node is a container + if (!this.getNodeModel().isContainer() && Object.keys(ports).length < 1) { + return; + } + this.__createUIPortConnections(this, isInput); + let label = { + isInput: isInput, + ui: this + }; + label.ui.isInput = isInput; + if (isInput) { + this.__inputPort["Input"] = label; + } else { + this.__outputPort["Output"] = label; + } + }, + + __createUIPortConnections: function(uiPort, isInput) { + [ + ["dragstart", "LinkDragStart"], + ["dragover", "LinkDragOver"], + ["drop", "LinkDrop"], + ["dragend", "LinkDragEnd"] + ].forEach(eventPair => { + uiPort.addListener(eventPair[0], e => { + const eData = { + event: e, + nodeId: this.getNodeId(), + isInput: isInput + }; + this.fireDataEvent(eventPair[1], eData); + }, this); + }, this); + }, + + getLinkPoint: function(port) { + if (port.isInput === true) { + console.log("Port should always be output"); + return null; + } + let nodeBounds = this.getCurrentBounds(); + if (nodeBounds === null) { + // not rendered yet + return null; + } + // It is always on the very left of the Desktop + let x = 0; + let y = nodeBounds.top + nodeBounds.height/2; + return [x, y]; + }, + + getCurrentBounds: function() { + let bounds = this.getBounds(); + let cel = this.getContentElement(); + if (cel) { + let domeEle = cel.getDomElement(); + if (domeEle) { + bounds.left = parseInt(domeEle.style.left); + bounds.top = parseInt(domeEle.style.top); + } + } + // NavigationBar height must be subtracted + // bounds.left = this.getContentLocation().left; + // bounds.top = this.getContentLocation().top; + return bounds; + } + } +}); diff --git a/services/web/client/source/class/qxapp/component/widget/NodePorts.js b/services/web/client/source/class/qxapp/component/widget/NodePorts.js new file mode 100644 index 00000000000..69dc143dae7 --- /dev/null +++ b/services/web/client/source/class/qxapp/component/widget/NodePorts.js @@ -0,0 +1,144 @@ +qx.Class.define("qxapp.component.widget.NodePorts", { + extend: qx.ui.core.Widget, + + construct: function(nodeModel) { + this.base(); + + let nodeInputLayout = new qx.ui.layout.VBox(10); + this._setLayout(nodeInputLayout); + + this.set({ + decorator: "main" + }); + + let atom = new qx.ui.basic.Atom().set({ + label: nodeModel.getLabel(), + center : true + }); + + this._add(atom); + + this.setNodeModel(nodeModel); + }, + + properties: { + nodeModel: { + check: "qxapp.data.model.NodeModel", + nullable: false + } + }, + + events: { + "PortDragStart": "qx.event.type.Data" + }, + + members: { + __inputPort: null, + __outputPort: null, + + getNodeId: function() { + return this.getNodeModel().getNodeId(); + }, + + getMetaData: function() { + return this.getNodeModel().getMetaData(); + }, + + populateNodeLayout: function() { + const metaData = this.getNodeModel().getMetaData(); + this.__inputPort = {}; + this.__outputPort = {}; + // this.__createUIPorts(true, metaData.inputs); + this.__createUIPorts(false, metaData.outputs); + }, + + getInputPort: function() { + return this.__inputPort["Input"]; + }, + + getOutputPort: function() { + return this.__outputPort["Output"]; + }, + + __createUIPorts: function(isInput, ports) { + // Always create ports if node is a container + if (!this.getNodeModel().isContainer() && Object.keys(ports).length < 1) { + return; + } + for (const portKey in ports) { + const port = ports[portKey]; + if (port.type.includes("api")) { + console.log("Provide widget for ", port.type); + } else { + let toolTip = new qx.ui.tooltip.ToolTip(port.description); + let portLabel = new qx.ui.basic.Label(port.label).set({ + draggable: true, + toolTip: toolTip, + textAlign: "right", + allowGrowX: true, + paddingRight: 20 + }); + this._add(portLabel); + this.__createUIPortConnections(portLabel, portKey); + let label = { + isInput: isInput, + ui: portLabel + }; + label.ui.isInput = isInput; + if (isInput) { + this.__inputPort["Input"] = label; + } else { + this.__outputPort["Output"] = label; + } + } + } + }, + + __createUIPortConnections: function(uiPort, portId) { + [ + ["dragstart", "PortDragStart"] + ].forEach(eventPair => { + uiPort.addListener(eventPair[0], e => { + const eData = { + event: e, + nodeId: this.getNodeId(), + portId: portId + }; + this.fireDataEvent(eventPair[1], eData); + }, this); + }, this); + }, + + getLinkPoint: function(port) { + if (port.isInput === true) { + console.log("Port should always be output"); + return null; + } + let nodeBounds = this.getCurrentBounds(); + if (nodeBounds === null) { + // not rendered yet + return null; + } + // It is always on the very left of the Desktop + let x = 0; + let y = nodeBounds.top + nodeBounds.height/2; + return [x, y]; + }, + + getCurrentBounds: function() { + let bounds = this.getBounds(); + let cel = this.getContentElement(); + if (cel) { + let domeEle = cel.getDomElement(); + if (domeEle) { + bounds.left = parseInt(domeEle.style.left); + bounds.top = parseInt(domeEle.style.top); + } + } + // NavigationBar height must be subtracted + // bounds.left = this.getContentLocation().left; + // bounds.top = this.getContentLocation().top; + return bounds; + } + } +}); diff --git a/services/web/client/source/class/qxapp/component/widget/NodeTreeItem.js b/services/web/client/source/class/qxapp/component/widget/NodeTreeItem.js new file mode 100644 index 00000000000..cb586907e65 --- /dev/null +++ b/services/web/client/source/class/qxapp/component/widget/NodeTreeItem.js @@ -0,0 +1,53 @@ +/* ************************************************************************ + + qxapp - the simcore frontent + + https://simcore.io + + Copyright: + 2019 IT'IS Foundation, https://itis.swiss + + License: + MIT: https://opensource.org/licenses/MIT + + Authors: + * Tobias Oetiker (oetiker) + +************************************************************************ */ + +qx.Class.define("qxapp.component.widget.NodeTreeItem", { + extend : qx.ui.tree.VirtualTreeItem, + + properties : { + nodeId : { + check : "String", + event: "changeNodeId", + nullable : true + } + }, + + members : { + _addWidgets : function() { + // Here's our indentation and tree-lines + this.addSpacer(); + this.addOpenButton(); + + // The standard tree icon follows + this.addIcon(); + + // The label + this.addLabel(); + + // All else should be right justified + this.addWidget(new qx.ui.core.Spacer(), { + flex: 1 + }); + + // Add a NodeId + var nodeIdWidget = new qx.ui.basic.Label(); + this.bind("nodeId", nodeIdWidget, "value"); + nodeIdWidget.setMaxWidth(250); + this.addWidget(nodeIdWidget); + } + } +}); diff --git a/services/web/client/source/class/qxapp/component/widget/SettingsView.js b/services/web/client/source/class/qxapp/component/widget/SettingsView.js new file mode 100644 index 00000000000..eb68ad1db00 --- /dev/null +++ b/services/web/client/source/class/qxapp/component/widget/SettingsView.js @@ -0,0 +1,253 @@ +const PORT_INPUTS_WIDTH = 300; + +qx.Class.define("qxapp.component.widget.SettingsView", { + extend: qx.ui.container.Composite, + + construct: function() { + this.base(); + + let hBox = new qx.ui.layout.HBox(10); + this.set({ + layout: hBox, + padding: 10 + }); + + let inputNodesLayout = this.__inputNodesLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(5)); + inputNodesLayout.set({ + width: PORT_INPUTS_WIDTH, + maxWidth: PORT_INPUTS_WIDTH, + allowGrowX: false + }); + const navBarLabelFont = qx.bom.Font.fromConfig(qxapp.theme.Font.fonts["nav-bar-label"]); + let inputLabel = new qx.ui.basic.Label(this.tr("Inputs")).set({ + font: navBarLabelFont, + alignX: "center" + }); + inputNodesLayout.add(inputLabel); + this.add(inputNodesLayout); + + + let mainLayout = this.__mainLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(10)); + mainLayout.set({ + alignX: "center", + padding: 70 + }); + this.add(mainLayout, { + flex: 1 + }); + + this.__nodesUI = []; + + this.__initTitle(); + this.__initSettings(); + this.__initButtons(); + }, + + events: { + "ShowViewer": "qx.event.type.Data" + }, + + properties: { + workbenchModel: { + check: "qxapp.data.model.WorkbenchModel", + nullable: false + }, + + nodeModel: { + check: "qxapp.data.model.NodeModel", + apply: "__applyNode" + } + }, + + members: { + __settingsBox: null, + __inputNodesLayout: null, + __mainLayout: null, + __nodesUI: null, + __startInteractive: null, + __openFoler: null, + + __initTitle: function() { + let box = new qx.ui.layout.HBox(); + box.set({ + spacing: 10, + alignX: "right" + }); + let titleBox = new qx.ui.container.Composite(box); + + let settLabel = new qx.ui.basic.Label(this.tr("Settings")); + settLabel.set({ + alignX: "center", + alignY: "middle" + }); + + titleBox.add(settLabel, { + width: "75%" + }); + this.__mainLayout.add(titleBox); + }, + + __initSettings: function() { + this.__settingsBox = new qx.ui.container.Composite(new qx.ui.layout.Grow()); + this.__mainLayout.add(this.__settingsBox); + }, + + __initButtons: function() { + let box = new qx.ui.layout.HBox(); + box.set({ + spacing: 10, + alignX: "right" + }); + let buttonsLayout = new qx.ui.container.Composite(box); + + let startInteractive = this.__startInteractive = new qx.ui.form.Button().set({ + icon: "@FontAwesome5Solid/sign-in-alt/32" + }); + + let openFolder = this.__openFoler = new qx.ui.form.Button().set({ + icon: "@FontAwesome5Solid/folder-open/32" + }); + openFolder.addListener("execute", function() { + let fileManager = new qxapp.component.widget.FileManager(this.getNodeModel()).set({ + width: 600, + height: 400 + }); + + let win = new qx.ui.window.Window(this.getNodeModel().getLabel()).set({ + layout: new qx.ui.layout.Canvas(), + contentPadding: 0, + showMinimize: false + }); + win.add(fileManager, { + top: 0, + right: 0, + bottom: 0, + left: 0 + }); + + win.center(); + win.open(); + }, this); + + buttonsLayout.add(startInteractive); + buttonsLayout.add(openFolder); + this.__mainLayout.add(buttonsLayout); + }, + + __getNodeUI: function(id) { + for (let i = 0; i < this.__nodesUI.length; i++) { + if (this.__nodesUI[i].getNodeUI() === id) { + return this.__nodesUI[i]; + } + } + return null; + }, + + __arePortsCompatible: function(node1, port1, node2, port2) { + return qxapp.data.Store.getInstance().arePortsCompatible(node1, port1, node2, port2); + }, + + __createDragDropMechanism: function(portUI) { + portUI.addListener("PortDragStart", e => { + let data = e.getData(); + let event = data.event; + let dragNodeId = data.nodeId; + let dragPortId = data.portId; + + // Register supported actions + event.addAction("copy"); + + // Register supported types + event.addType("osparc-port-link"); + let dragData = { + dragNodeId: dragNodeId, + dragPortId: dragPortId + }; + event.addData("osparc-port-link", dragData); + }, this); + + portUI.addListener("PortDragOver", e => { + let data = e.getData(); + let event = data.event; + // let dropNodeId = data.nodeId; + let dropNodeId = this.getNodeModel().getNodeId(); + let dropPortId = data.portId; + + let compatible = false; + if (event.supportsType("osparc-port-link")) { + const dragNodeId = event.getData("osparc-port-link").dragNodeId; + const dragPortId = event.getData("osparc-port-link").dragPortId; + compatible = this.__arePortsCompatible(dragNodeId, dragPortId, dropNodeId, dropPortId); + } + + if (!compatible) { + event.preventDefault(); + } + }, this); + + portUI.addListener("PortDrop", e => { + let data = e.getData(); + let event = data.event; + // let dropNodeId = data.nodeId; + let dropPortId = data.portId; + + if (event.supportsType("osparc-port-link")) { + let dragNodeId = event.getData("osparc-port-link").dragNodeId; + let dragPortId = event.getData("osparc-port-link").dragPortId; + this.getNodeModel().addPortLink(dropPortId, dragNodeId, dragPortId); + } + }, this); + }, + + __createInputPortsUI: function(inputNodeModel) { + let nodePorts = new qxapp.component.widget.NodePorts(inputNodeModel); + nodePorts.populateNodeLayout(); + this.__createDragDropMechanism(nodePorts); + this.__inputNodesLayout.add(nodePorts, { + flex: 1 + }); + return nodePorts; + }, + + __createInputPortsUIs: function(nodeModel) { + const inputNodes = nodeModel.getInputNodes(); + for (let i=0; i 1) { + this.__inputNodesLayout.removeAt(this.__inputNodesLayout.getChildren().length-1); + } + }, + + __applyNode: function(nodeModel, oldNode, propertyName) { + this.__settingsBox.removeAll(); + this.__settingsBox.add(nodeModel.getPropsWidget()); + this.__createDragDropMechanism(nodeModel.getPropsWidget()); + + this.__clearInputPortsUIs(); + this.__createInputPortsUIs(nodeModel); + + let viewerButton = nodeModel.getViewerButton(); + if (viewerButton) { + nodeModel.addListenerOnce("ShowViewer", e => { + const data = e.getData(); + this.fireDataEvent("ShowViewer", data); + }, this); + this.__startInteractive = viewerButton; + } + } + } +}); diff --git a/services/web/client/source/class/qxapp/component/widget/TreeTool.js b/services/web/client/source/class/qxapp/component/widget/TreeTool.js new file mode 100644 index 00000000000..f0601ba47bb --- /dev/null +++ b/services/web/client/source/class/qxapp/component/widget/TreeTool.js @@ -0,0 +1,123 @@ +/* eslint no-warning-comments: "off" */ + +qx.Class.define("qxapp.component.widget.TreeTool", { + extend: qx.ui.core.Widget, + + construct: function(projectName, workbenchModel) { + this.base(arguments); + + let treeLayout = new qx.ui.layout.VBox(10); + this._setLayout(treeLayout); + + this.set({ + projectName: projectName, + workbenchModel: workbenchModel + }); + + this.__buildLayout(); + this.buildTree(); + }, + + events: { + "NodeDoubleClicked": "qx.event.type.Data" + }, + + properties: { + workbenchModel: { + check: "qxapp.data.model.WorkbenchModel", + nullable: false + }, + + projectName: { + check: "String" + } + }, + + members: { + __tree: null, + __selectedNodeId: null, + + __buildLayout: function() { + let tree = this.__tree = new qx.ui.tree.VirtualTree(null, "label", "children").set({ + openMode: "none" + }); + + this._removeAll(); + this._add(tree, { + flex: 1 + }); + + this.__tree.addListener("dblclick", e => { + let selection = this.__tree.getSelection(); + let currentSelection = selection.toArray(); + if (currentSelection.length > 0) { + let selectedRow = currentSelection[0]; + this.fireDataEvent("NodeDoubleClicked", selectedRow.getNodeId()); + } + }, this); + }, + + buildTree: function() { + const topLevelNodes = this.getWorkbenchModel().getNodeModels(); + let data = { + label: this.getProjectName(), + children: this.__convertModel(topLevelNodes), + nodeId: "root", + isContainer: true + }; + let newModel = qx.data.marshal.Json.createModel(data, true); + let oldModel = this.__tree.getModel(); + if (JSON.stringify(newModel) !== JSON.stringify(oldModel)) { + this.__tree.setModel(newModel); + this.__tree.setDelegate({ + createItem: () => new qxapp.component.widget.NodeTreeItem(), + bindItem: (c, item, id) => { + c.bindDefaultProperties(item, id); + c.bindProperty("nodeId", "nodeId", null, item, id); + } + }); + } + }, + + __convertModel: function(nodes) { + let children = []; + for (let nodeId in nodes) { + const node = nodes[nodeId]; + let nodeInTree = { + label: "", + nodeId: node.getNodeId() + }; + nodeInTree.label = node.getLabel(); + nodeInTree.isContainer = node.isContainer(); + if (node.isContainer()) { + nodeInTree.children = this.__convertModel(node.getInnerNodes()); + } + children.push(nodeInTree); + } + return children; + }, + + __getNodeInTree: function(model, nodeId) { + if (model.getNodeId() === nodeId) { + return model; + } else if (model.getIsContainer() && model.getChildren() !== null) { + let node = null; + let children = model.getChildren().toArray(); + for (let i=0; node === null && i < children.length; i++) { + node = this.__getNodeInTree(children[i], nodeId); + } + return node; + } + return null; + }, + + nodeSelected: function(nodeId) { + const dataModel = this.__tree.getModel(); + let nodeInTree = this.__getNodeInTree(dataModel, nodeId); + if (nodeInTree) { + this.__tree.openNodeAndParents(nodeInTree); + this.__tree.setSelection(new qx.data.Array([nodeInTree])); + } + } + } +}); diff --git a/services/web/client/source/class/qxapp/component/widget/WidgetManager.js b/services/web/client/source/class/qxapp/component/widget/WidgetManager.js new file mode 100644 index 00000000000..e2c38ba32b9 --- /dev/null +++ b/services/web/client/source/class/qxapp/component/widget/WidgetManager.js @@ -0,0 +1,16 @@ +qx.Class.define("qxapp.component.widget.WidgetManager", { + extend: qx.core.Object, + + type: "singleton", + + members: { + getWidgetForNode: function(node) { + let nodeKey = node.getMetaData().key; + if (nodeKey.includes("file-picker")) { + let filePicker = new qxapp.component.widget.FilePicker(node); + return filePicker; + } + return null; + } + } +}); diff --git a/services/web/client/source/class/qxapp/components/workbench/logger/LoggerView.js b/services/web/client/source/class/qxapp/component/widget/logger/LoggerView.js similarity index 90% rename from services/web/client/source/class/qxapp/components/workbench/logger/LoggerView.js rename to services/web/client/source/class/qxapp/component/widget/logger/LoggerView.js index 9276aea237f..e5f5fb631a5 100644 --- a/services/web/client/source/class/qxapp/components/workbench/logger/LoggerView.js +++ b/services/web/client/source/class/qxapp/component/widget/logger/LoggerView.js @@ -8,30 +8,23 @@ const LOG_LEVEL = { }; Object.freeze(LOG_LEVEL); -qx.Class.define("qxapp.components.workbench.logger.LoggerView", { - extend: qx.ui.window.Window, +qx.Class.define("qxapp.component.widget.logger.LoggerView", { + extend: qx.ui.core.Widget, construct: function() { this.base(); - this.set({ - showMinimize: false, - showStatusbar: false, - width: 800, - height: 300, - caption: "Logger", - layout: new qx.ui.layout.VBox(10) - }); + this._setLayout(new qx.ui.layout.VBox(10)); let filterLayout = new qx.ui.container.Composite(new qx.ui.layout.HBox(10)); let clearButton = new qx.ui.form.Button("Clear"); - clearButton.addListener("execute", function(e) { + clearButton.addListener("execute", e => { this.clearLogger(); }, this); filterLayout.add(clearButton); - let searchLabel = new qx.ui.basic.Label("Filter"); + let searchLabel = new qx.ui.basic.Label(this.tr("Filter")); filterLayout.add(searchLabel); this.__textfield = new qx.ui.form.TextField(); this.__textfield.setLiveUpdate(true); @@ -59,7 +52,7 @@ qx.Class.define("qxapp.components.workbench.logger.LoggerView", { if (this.getLogLevel() === logLevelBtn.logLevel) { defSelected.push(logLevelBtn); } - logLevelBtn.addListener("changeValue", function(e) { + logLevelBtn.addListener("changeValue", e => { if (e.getData() === true) { this.setLogLevel(logLevelBtn.logLevel); } @@ -68,10 +61,10 @@ qx.Class.define("qxapp.components.workbench.logger.LoggerView", { group.setSelection(defSelected); group.setAllowEmptySelection(false); - this.add(filterLayout); + this._add(filterLayout); // let tableModel = this.__logModel = new qx.ui.table.model.Filtered(); - let tableModel = this.__logModel = new qxapp.components.workbench.logger.RemoteTableModel(); + let tableModel = this.__logModel = new qxapp.component.widget.logger.RemoteTableModel(); tableModel.setColumns(["Origin", "Message"], ["whoRich", "whatRich"]); let custom = { @@ -92,7 +85,7 @@ qx.Class.define("qxapp.components.workbench.logger.LoggerView", { resizeBehavior.setWidth(0, "15%"); resizeBehavior.setWidth(1, "85%"); - this.add(table, { + this._add(table, { flex: 1 }); diff --git a/services/web/client/source/class/qxapp/components/workbench/logger/RemoteTableModel.js b/services/web/client/source/class/qxapp/component/widget/logger/RemoteTableModel.js similarity index 98% rename from services/web/client/source/class/qxapp/components/workbench/logger/RemoteTableModel.js rename to services/web/client/source/class/qxapp/component/widget/logger/RemoteTableModel.js index b54b35f123f..ffa2bdca38d 100644 --- a/services/web/client/source/class/qxapp/components/workbench/logger/RemoteTableModel.js +++ b/services/web/client/source/class/qxapp/component/widget/logger/RemoteTableModel.js @@ -27,7 +27,7 @@ /* eslint no-underscore-dangle: "off" */ -qx.Class.define("qxapp.components.workbench.logger.RemoteTableModel", { +qx.Class.define("qxapp.component.widget.logger.RemoteTableModel", { extend : qx.ui.table.model.Remote, diff --git a/services/web/client/source/class/qxapp/components/workbench/LinkBase.js b/services/web/client/source/class/qxapp/component/workbench/LinkBase.js similarity index 72% rename from services/web/client/source/class/qxapp/components/workbench/LinkBase.js rename to services/web/client/source/class/qxapp/component/workbench/LinkBase.js index 1b5a42cfdca..07ac561a347 100644 --- a/services/web/client/source/class/qxapp/components/workbench/LinkBase.js +++ b/services/web/client/source/class/qxapp/component/workbench/LinkBase.js @@ -1,4 +1,4 @@ -qx.Class.define("qxapp.components.workbench.LinkBase", { +qx.Class.define("qxapp.component.workbench.LinkBase", { extend: qx.core.Object, construct: function(representation) { @@ -25,17 +25,9 @@ qx.Class.define("qxapp.components.workbench.LinkBase", { init: null, check: "String" }, - inputPortId: { - init: null, - check: "String" - }, outputNodeId: { init: null, check: "String" - }, - outputPortId: { - init: null, - check: "String" } } }); diff --git a/services/web/client/source/class/qxapp/component/workbench/NodeBase.js b/services/web/client/source/class/qxapp/component/workbench/NodeBase.js new file mode 100644 index 00000000000..14a58d54aba --- /dev/null +++ b/services/web/client/source/class/qxapp/component/workbench/NodeBase.js @@ -0,0 +1,230 @@ +const nodeWidth = 180; +const portHeight = 16; + +qx.Class.define("qxapp.component.workbench.NodeBase", { + extend: qx.ui.window.Window, + + construct: function(nodeModel) { + this.base(); + + this.set({ + appearance: "window-small-cap", + showMinimize: false, + showMaximize: false, + showClose: false, + showStatusbar: false, + resizable: false, + allowMaximize: false, + minWidth: nodeWidth, + maxWidth: nodeWidth + }); + + this.setNodeModel(nodeModel); + }, + + properties: { + nodeModel: { + check: "qxapp.data.model.NodeModel", + nullable: false + } + }, + + events: { + "LinkDragStart": "qx.event.type.Data", + "LinkDragOver": "qx.event.type.Data", + "LinkDrop": "qx.event.type.Data", + "LinkDragEnd": "qx.event.type.Data", + "NodeMoving": "qx.event.type.Event" + }, + + members: { + __inputPortLayout: null, + __outputPortLayout: null, + __inputPort: null, + __outputPort: null, + __progressLabel: null, + __progressBar: null, + + getNodeId: function() { + return this.getNodeModel().getNodeId(); + }, + + getMetaData: function() { + return this.getNodeModel().getMetaData(); + }, + + createNodeLayout: function() { + let nodeLayout = new qx.ui.layout.VBox(5, null, "separator-vertical"); + this.setLayout(nodeLayout); + + let inputsOutputsLayout = new qx.ui.container.Composite(new qx.ui.layout.HBox()); + this.add(inputsOutputsLayout, { + flex: 1 + }); + + let inputsBox = new qx.ui.layout.VBox(5); + this.__inputPortLayout = new qx.ui.container.Composite(inputsBox); + inputsOutputsLayout.add(this.__inputPortLayout, { + width: "50%" + }); + + let outputsBox = new qx.ui.layout.VBox(5); + this.__outputPortLayout = new qx.ui.container.Composite(outputsBox); + inputsOutputsLayout.add(this.__outputPortLayout, { + width: "50%" + }); + + + let progressBox = new qx.ui.container.Composite(new qx.ui.layout.Basic()); + progressBox.setMinWidth(nodeWidth-20); + + this.__progressBar = new qx.ui.indicator.ProgressBar(); + this.__progressBar.setWidth(nodeWidth-20); + progressBox.add(this.__progressBar, { + top: 0, + left: 0 + }); + + this.__progressLabel = new qx.ui.basic.Label("0%"); + progressBox.add(this.__progressLabel, { + top: 3, + left: nodeWidth/2 - 20 + }); + + this.add(progressBox); + }, + + populateNodeLayout: function() { + const nodeModel = this.getNodeModel(); + const metaData = nodeModel.getMetaData(); + this.setCaption(nodeModel.getLabel()); + this.__inputPort = {}; + this.__outputPort = {}; + this.__createUIPorts(true, metaData.inputs); + this.__createUIPorts(false, metaData.outputs); + }, + + getInputPort: function() { + return this.__inputPort["Input"]; + }, + + getOutputPort: function() { + return this.__outputPort["Output"]; + }, + + __createUIPorts: function(isInput, ports) { + // Always create ports if node is a container + if (!this.getNodeModel().isContainer() && Object.keys(ports).length < 1) { + return; + } + let portUI = this.__createUIPort(isInput); + this.__createUIPortConnections(portUI, isInput); + let label = { + isInput: isInput, + ui: portUI + }; + label.ui.isInput = isInput; + if (isInput) { + this.__inputPort["Input"] = label; + this.__inputPortLayout.add(label.ui); + } else { + this.__outputPort["Output"] = label; + this.__outputPortLayout.add(label.ui); + } + }, + + __createUIPort: function(isInput) { + const labelText = (isInput) ? "Input(s)" : "Output(s)"; + const alignX = (isInput) ? "left" : "right"; + let uiPort = new qx.ui.basic.Atom(labelText).set({ + height: portHeight, + draggable: true, + droppable: true, + alignX: alignX, + allowGrowX: false + }); + return uiPort; + }, + + __createUIPortConnections: function(uiPort, isInput) { + [ + ["dragstart", "LinkDragStart"], + ["dragover", "LinkDragOver"], + ["drop", "LinkDrop"], + ["dragend", "LinkDragEnd"] + ].forEach(eventPair => { + uiPort.addListener(eventPair[0], e => { + const eData = { + event: e, + nodeId: this.getNodeId(), + isInput: isInput + }; + this.fireDataEvent(eventPair[1], eData); + }, this); + }, this); + }, + + getLinkPoint: function(port) { + let nodeBounds = this.getCurrentBounds(); + if (nodeBounds === null) { + // not rendered yet + return null; + } + let x = nodeBounds.left; + if (port.isInput === false) { + x += nodeBounds.width; + } else { + // hack to place the arrow-head properly + x -= 6; + } + + const captionHeight = this.__childControls.captionbar.getBounds().height; + const inputOutputs = this.getChildren()[0]; + let ports = null; + if (port.isInput) { + ports = inputOutputs.getChildren()[0].getChildren(); + } else { + ports = inputOutputs.getChildren()[1].getChildren(); + } + let portBounds; + if (ports.length > 0) { + portBounds = ports[0].getBounds(); + } + let y = nodeBounds.top + captionHeight + 10 + portBounds.top + portBounds.height/2; + return [x, y]; + }, + + getCurrentBounds: function() { + let bounds = this.getBounds(); + let cel = this.getContentElement(); + if (cel) { + let domeEle = cel.getDomElement(); + if (domeEle) { + bounds.left = parseInt(domeEle.style.left); + bounds.top = parseInt(domeEle.style.top); + } + } + // NavigationBar height must be subtracted + // bounds.left = this.getContentLocation().left; + // bounds.top = this.getContentLocation().top; + return bounds; + }, + + setProgress: function(progress) { + this.__progressLabel.setValue(progress + "%"); + this.__progressBar.setValue(progress); + }, + + getProgress: function() { + return this.__progressBar.getValue(); + }, + + // override qx.ui.window.Window "move" event listener + _onMovePointerMove: function(e) { + this.base(arguments, e); + if (e.getPropagationStopped() === true) { + this.fireEvent("NodeMoving"); + } + } + } +}); diff --git a/services/web/client/source/class/qxapp/components/workbench/SvgWidget.js b/services/web/client/source/class/qxapp/component/workbench/SvgWidget.js similarity index 80% rename from services/web/client/source/class/qxapp/components/workbench/SvgWidget.js rename to services/web/client/source/class/qxapp/component/workbench/SvgWidget.js index 7274f2e9b76..6a43eae164a 100644 --- a/services/web/client/source/class/qxapp/components/workbench/SvgWidget.js +++ b/services/web/client/source/class/qxapp/component/workbench/SvgWidget.js @@ -1,4 +1,4 @@ -qx.Class.define("qxapp.components.workbench.SvgWidget", { +qx.Class.define("qxapp.component.workbench.SvgWidget", { extend: qx.ui.core.Widget, construct: function(svgLayerId) { @@ -23,8 +23,7 @@ qx.Class.define("qxapp.components.workbench.SvgWidget", { __svgWrapper: null, __linksCanvas: null, - __getControls: function(x1, y1, x2, y2) { - const offset = 60; + __getControls: function(x1, y1, x2, y2, offset = 60) { return [{ x: x1, y: y1 @@ -45,6 +44,12 @@ qx.Class.define("qxapp.components.workbench.SvgWidget", { return this.__svgWrapper.drawCurve(this.__linksCanvas, controls); }, + drawCurveMini: function(x1, y1, x2, y2) { + const offset = 20; + const controls = this.__getControls(x1, y1, x2, y2, offset); + return this.__svgWrapper.drawCurveMini(this.__linksCanvas, controls); + }, + updateCurve: function(curve, x1, y1, x2, y2) { const controls = this.__getControls(x1, y1, x2, y2); this.__svgWrapper.updateCurve(curve, controls); diff --git a/services/web/client/source/class/qxapp/component/workbench/WorkbenchView.js b/services/web/client/source/class/qxapp/component/workbench/WorkbenchView.js new file mode 100644 index 00000000000..52e6e23a7b6 --- /dev/null +++ b/services/web/client/source/class/qxapp/component/workbench/WorkbenchView.js @@ -0,0 +1,843 @@ +/* eslint no-warning-comments: "off" */ +/* global window */ + +const BUTTON_SIZE = 50; +const BUTTON_SPACING = 10; +const NODE_INPUTS_WIDTH = 200; + +qx.Class.define("qxapp.component.workbench.WorkbenchView", { + extend: qx.ui.container.Composite, + + construct: function(workbenchModel) { + this.base(); + + let hBox = new qx.ui.layout.HBox(); + this.set({ + layout: hBox + }); + + let inputNodesLayout = this.__inputNodesLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(5)); + inputNodesLayout.set({ + width: NODE_INPUTS_WIDTH, + maxWidth: NODE_INPUTS_WIDTH, + allowGrowX: false + }); + const navBarLabelFont = qx.bom.Font.fromConfig(qxapp.theme.Font.fonts["nav-bar-label"]); + let inputLabel = new qx.ui.basic.Label(this.tr("Inputs")).set({ + font: navBarLabelFont, + alignX: "center" + }); + inputNodesLayout.add(inputLabel); + this.add(inputNodesLayout); + + this.__desktopCanvas = new qx.ui.container.Composite(new qx.ui.layout.Canvas()); + this.add(this.__desktopCanvas, { + flex : 1 + }); + + let nodesExposedLayout = this.__outputNodesLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(5)); + nodesExposedLayout.set({ + width: NODE_INPUTS_WIDTH, + maxWidth: NODE_INPUTS_WIDTH, + allowGrowX: false + }); + let outputLabel = new qx.ui.basic.Label(this.tr("Outputs")).set({ + font: navBarLabelFont, + alignX: "center" + }); + nodesExposedLayout.add(outputLabel); + this.add(nodesExposedLayout); + + this.__desktop = new qx.ui.window.Desktop(new qx.ui.window.Manager()); + this.__desktopCanvas.add(this.__desktop, { + left: 0, + top: 0, + right: 0, + bottom: 0 + }); + + this.setWorkbenchModel(workbenchModel); + this.__svgWidget = new qxapp.component.workbench.SvgWidget("SvgWidgetLayer"); + // this gets fired once the widget has appeared and the library has been loaded + // due to the qx rendering, this will always happen after setup, so we are + // sure to catch this event + this.__svgWidget.addListenerOnce("SvgWidgetReady", () => { + // Will be called only the first time Svg lib is loaded + this.removeAll(); + this.loadModel(this.getWorkbenchModel()); + this.fireDataEvent("NodeDoubleClicked", "root"); + }); + + this.__desktop.add(this.__svgWidget, { + left: 0, + top: 0, + right: 0, + bottom: 0 + }); + + this.__desktop.addListener("click", e => { + this.__selectedItemChanged(null); + }, this); + + this.__desktop.addListener("changeActiveWindow", e => { + let winEmitting = e.getData(); + if (winEmitting && winEmitting.isActive() && winEmitting.classname.includes("workbench.Node")) { + this.__selectedItemChanged(winEmitting.getNodeId()); + } else { + this.__selectedItemChanged(null); + } + }, this); + + this.__nodesUI = []; + this.__linksUI = []; + + let buttonContainer = new qx.ui.container.Composite(new qx.ui.layout.HBox(BUTTON_SPACING)); + this.__desktopCanvas.add(buttonContainer, { + bottom: 10, + right: 10 + }); + [ + this.__getPlusButton(), + this.__getRemoveButton() + ].forEach(widget => { + buttonContainer.add(widget); + }); + + this.addListener("dblclick", function(pointerEvent) { + // FIXME: + const navBarHeight = 50; + let x = pointerEvent.getViewportLeft() - this.getBounds().left; + let y = pointerEvent.getViewportTop() - navBarHeight; + + let srvCat = new qxapp.component.workbench.servicesCatalogue.ServicesCatalogue(); + srvCat.moveTo(x, y); + srvCat.open(); + let pos = { + x: x, + y: y + }; + srvCat.addListener("AddService", e => { + this.__addServiceFromCatalogue(e, pos); + }, this); + }, this); + }, + + events: { + "NodeDoubleClicked": "qx.event.type.Data" + }, + + properties: { + workbenchModel: { + check: "qxapp.data.model.WorkbenchModel", + nullable: false + } + }, + + members: { + __nodesUI: null, + __linksUI: null, + __inputNodesLayout: null, + __outputNodesLayout: null, + __desktop: null, + __svgWidget: null, + __tempLinkNodeId: null, + __tempLinkRepr: null, + __pointerPosX: null, + __pointerPosY: null, + __selectedItemId: null, + __playButton: null, + __stopButton: null, + __currentModel: null, + + __getPlusButton: function() { + const icon = "@FontAwesome5Solid/plus/32"; // qxapp.dev.Placeholders.getIcon("fa-plus", 32); + let plusButton = new qx.ui.form.Button(null, icon); + plusButton.set({ + width: BUTTON_SIZE, + height: BUTTON_SIZE + }); + plusButton.addListener("execute", function() { + let srvCat = new qxapp.component.workbench.servicesCatalogue.ServicesCatalogue(); + srvCat.center(); + srvCat.open(); + srvCat.addListener("AddService", e => { + this.__addServiceFromCatalogue(e); + }, this); + }, this); + return plusButton; + }, + + __getRemoveButton: function() { + const icon = "@FontAwesome5Solid/trash/32"; + let removeButton = new qx.ui.form.Button(null, icon); + removeButton.set({ + width: BUTTON_SIZE, + height: BUTTON_SIZE + }); + removeButton.addListener("execute", function() { + if (this.__selectedItemId && this.__isSelectedItemALink(this.__selectedItemId)) { + this.__removeLink(this.__getLink(this.__selectedItemId)); + this.__selectedItemId = null; + } else { + this.__removeSelectedNode(); + } + }, this); + return removeButton; + }, + + __addServiceFromCatalogue: function(e, pos) { + let data = e.getData(); + let metaData = data.service; + let nodeAId = data.contextNodeId; + let portA = data.contextPort; + + let nodeModel = this.getWorkbenchModel().createNodeModel(metaData.key, metaData.version); + let parent = null; + if (this.__currentModel.isContainer()) { + parent = this.__currentModel; + } + this.getWorkbenchModel().addNodeModel(nodeModel, parent); + + let nodeB = this.__createNodeUI(nodeModel.getNodeId()); + this.__addNodeToWorkbench(nodeB, pos); + + if (nodeAId !== null && portA !== null) { + let nodeBId = nodeB.getNodeId(); + let portB = this.__findCompatiblePort(nodeB, portA); + // swap node-ports to have node1 as input and node2 as output + if (portA.isInput) { + [nodeAId, portA, nodeBId, portB] = [nodeBId, portB, nodeAId, portA]; + } + this.__createLinkBetweenNodes({ + nodeUuid: nodeAId + }, { + nodeUuid: nodeBId + }); + } + }, + + __addNodeToWorkbench: function(node, position) { + if (position === undefined || position === null) { + position = {}; + let farthestRight = 0; + for (let i=0; i < this.__nodesUI.length; i++) { + let boundPos = this.__nodesUI[i].getBounds(); + let rightPos = boundPos.left + boundPos.width; + if (farthestRight < rightPos) { + farthestRight = rightPos; + } + } + position.x = 50 + farthestRight; + position.y = 200; + } + node.getNodeModel().setPosition(position.x, position.y); + node.moveTo(position.x, position.y); + this.addWindowToDesktop(node); + this.__nodesUI.push(node); + + node.addListener("NodeMoving", function() { + this.__updateLinks(node); + }, this); + + node.addListener("appear", function() { + this.__updateLinks(node); + }, this); + + node.addListener("dblclick", e => { + this.fireDataEvent("NodeDoubleClicked", node.getNodeId()); + e.stopPropagation(); + }, this); + + // qx.ui.core.queue.Widget.flush(); + qx.ui.core.queue.Layout.flush(); + }, + + __createNodeUI: function(nodeId) { + let nodeModel = this.getWorkbenchModel().getNodeModel(nodeId); + + let nodeBase = new qxapp.component.workbench.NodeBase(nodeModel); + nodeBase.createNodeLayout(); + nodeBase.populateNodeLayout(); + this.__createDragDropMechanism(nodeBase); + return nodeBase; + }, + + __createDragDropMechanism: function(nodeBase) { + const evType = "pointermove"; + nodeBase.addListener("LinkDragStart", e => { + let data = e.getData(); + let event = data.event; + let dragNodeId = data.nodeId; + let dragIsInput = data.isInput; + + // Register supported actions + event.addAction("move"); + + // Register supported types + event.addType("osparc-node-link"); + let dragData = { + dragNodeId: dragNodeId, + dragIsInput: dragIsInput + }; + event.addData("osparc-node-link", dragData); + + this.__tempLinkNodeId = dragData.dragNodeId; + this.__tempLinkIsInput = dragData.dragIsInput; + qx.bom.Element.addListener( + this.__desktop, + evType, + this.__startTempLink, + this + ); + }, this); + + nodeBase.addListener("LinkDragOver", e => { + let data = e.getData(); + let event = data.event; + let dropNodeId = data.nodeId; + let dropIsInput = data.isInput; + + let compatible = false; + if (event.supportsType("osparc-node-link")) { + const dragNodeId = event.getData("osparc-node-link").dragNodeId; + const dragIsInput = event.getData("osparc-node-link").dragIsInput; + const dragNode = this.getNodeUI(dragNodeId); + const dropNode = this.getNodeUI(dropNodeId); + const dragPortTarget = dragIsInput ? dragNode.getInputPort() : dragNode.getOutputPort(); + const dropPortTarget = dropIsInput ? dropNode.getInputPort() : dropNode.getOutputPort(); + compatible = this.__areNodesCompatible(dragPortTarget, dropPortTarget); + } + + if (!compatible) { + event.preventDefault(); + } + }, this); + + nodeBase.addListener("LinkDrop", e => { + let data = e.getData(); + let event = data.event; + let dropNodeId = data.nodeId; + let dropIsInput = data.isInput; + + if (event.supportsType("osparc-node-link")) { + let dragNodeId = event.getData("osparc-node-link").dragNodeId; + let dragIsInput = event.getData("osparc-node-link").dragIsInput; + + let nodeAId = dropIsInput ? dragNodeId : dropNodeId; + let nodeBId = dragIsInput ? dragNodeId : dropNodeId; + + this.__createLinkBetweenNodes({ + nodeUuid: nodeAId + }, { + nodeUuid: nodeBId + }); + this.__removeTempLink(); + qx.bom.Element.removeListener( + this.__desktop, + evType, + this.__startTempLink, + this + ); + } + }, this); + + nodeBase.addListener("LinkDragEnd", e => { + let data = e.getData(); + let dragNodeId = data.nodeId; + + let posX = this.__pointerPosX; + let posY = this.__pointerPosY; + if (this.__tempLinkNodeId === dragNodeId) { + let srvCat = new qxapp.component.workbench.servicesCatalogue.ServicesCatalogue(); + if (this.__tempLinkIsInput === true) { + srvCat.setContext(dragNodeId, this.getNodeUI(dragNodeId).getInputPort()); + } else { + srvCat.setContext(dragNodeId, this.getNodeUI(dragNodeId).getOutputPort()); + } + srvCat.moveTo(posX, posY); + srvCat.open(); + let pos = { + x: posX, + y: posY + }; + srvCat.addListener("AddService", function(ev) { + this.__addServiceFromCatalogue(ev, pos); + }, this); + srvCat.addListener("close", function(ev) { + this.__removeTempLink(); + }, this); + } + qx.bom.Element.removeListener( + this.__desktop, + evType, + this.__startTempLink, + this + ); + }, this); + }, + + __createInputNodeUI: function(inputNodeModel) { + let nodeInput = new qxapp.component.widget.NodeInput(inputNodeModel); + nodeInput.populateNodeLayout(); + this.__createDragDropMechanism(nodeInput); + this.__inputNodesLayout.add(nodeInput, { + flex: 1 + }); + return nodeInput; + }, + + __createInputNodeUIs: function(model) { + const inputNodes = model.getInputNodes(); + for (let i=0; i 1) { + this.__inputNodesLayout.removeAt(this.__inputNodesLayout.getChildren().length-1); + } + }, + + __createNodeExposedUI: function(currentModel) { + let nodeOutput = new qxapp.component.widget.NodeExposed(currentModel); + nodeOutput.populateNodeLayout(); + this.__createDragDropMechanism(nodeOutput); + this.__outputNodesLayout.add(nodeOutput, { + flex: 1 + }); + return nodeOutput; + }, + + __createNodeExposedUIs: function(model) { + let outputLabel = this.__createNodeExposedUI(model); + this.__nodesUI.push(outputLabel); + }, + + __clearNodeExposedUIs: function() { + // remove all but the title + while (this.__outputNodesLayout.getChildren().length > 1) { + this.__outputNodesLayout.removeAt(this.__outputNodesLayout.getChildren().length-1); + } + }, + + __removeSelectedNode: function() { + for (let i=0; i { + // this is needed to get out of the context of svg + link.fireDataEvent("linkSelected", link.getLinkId()); + e.stopPropagation(); + }, this); + + link.addListener("linkSelected", e => { + this.__selectedItemChanged(link.getLinkId()); + }, this); + + return link; + }, + + __createLinkBetweenNodes: function(from, to, linkId) { + let node1Id = from.nodeUuid; + let node2Id = to.nodeUuid; + this.__createLink(node1Id, node2Id, linkId); + }, + + __createLinkBetweenNodesAndInputNodes: function(from, to, linkId) { + const inputNodes = this.__inputNodesLayout.getChildren(); + // Children[0] is the title + for (let i=1; i { + let link = this.__getLink(linkId); + if (link) { + let node1 = this.getNodeUI(link.getInputNodeId()); + let port1 = node1.getOutputPort(); + let node2 = this.getNodeUI(link.getOutputNodeId()); + let port2 = node2.getInputPort(); + const pointList = this.__getLinkPoints(node1, port1, node2, port2); + const x1 = pointList[0][0]; + const y1 = pointList[0][1]; + const x2 = pointList[1][0]; + const y2 = pointList[1][1]; + this.__svgWidget.updateCurve(link.getRepresentation(), x1, y1, x2, y2); + } + }); + }, + + __startTempLink: function(pointerEvent) { + if (this.__tempLinkNodeId === null) { + return; + } + let node = this.getNodeUI(this.__tempLinkNodeId); + if (node === null) { + return; + } + let port; + if (this.__tempLinkIsInput) { + port = node.getInputPort(); + } else { + port = node.getOutputPort(); + } + if (port === null) { + return; + } + + let x1; + let y1; + let x2; + let y2; + const portPos = node.getLinkPoint(port); + // FIXME: + const navBarHeight = 50; + const inputNodesLayoutWidth = this.__inputNodesLayout.isVisible() ? this.__inputNodesLayout.getWidth() : 0; + this.__pointerPosX = pointerEvent.getViewportLeft() - this.getBounds().left - inputNodesLayoutWidth; + this.__pointerPosY = pointerEvent.getViewportTop() - navBarHeight; + + if (port.isInput) { + x1 = this.__pointerPosX; + y1 = this.__pointerPosY; + x2 = portPos[0]; + y2 = portPos[1]; + } else { + x1 = portPos[0]; + y1 = portPos[1]; + x2 = this.__pointerPosX; + y2 = this.__pointerPosY; + } + + if (this.__tempLinkRepr === null) { + this.__tempLinkRepr = this.__svgWidget.drawCurve(x1, y1, x2, y2); + } else { + this.__svgWidget.updateCurve(this.__tempLinkRepr, x1, y1, x2, y2); + } + }, + + __removeTempLink: function() { + if (this.__tempLinkRepr !== null) { + this.__svgWidget.removeCurve(this.__tempLinkRepr); + } + this.__tempLinkRepr = null; + this.__tempLinkNodeId = null; + this.__pointerPosX = null; + this.__pointerPosY = null; + }, + + __getLinkPoints: function(node1, port1, node2, port2) { + let p1 = null; + let p2 = null; + // swap node-ports to have node1 as input and node2 as output + if (port1.isInput) { + [node1, port1, node2, port2] = [node2, port2, node1, port1]; + } + p1 = node1.getLinkPoint(port1); + if (this.__currentModel.isContainer() && node2.getNodeModel().getNodeId() === this.__currentModel.getNodeId()) { + // connection to the exposed output + const dc = this.__desktopCanvas.getBounds(); + const onl = this.__outputNodesLayout.getBounds(); + p2 = [ + parseInt(dc.width - 6), + parseInt(onl.height / 2) + ]; + } else { + p2 = node2.getLinkPoint(port2); + } + return [p1, p2]; + }, + + getNodeUI: function(id) { + for (let i = 0; i < this.__nodesUI.length; i++) { + if (this.__nodesUI[i].getNodeId() === id) { + return this.__nodesUI[i]; + } + } + return null; + }, + + __getConnectedLinks: function(nodeId) { + let connectedLinks = []; + for (let i = 0; i < this.__linksUI.length; i++) { + if (this.__linksUI[i].getInputNodeId() === nodeId) { + connectedLinks.push(this.__linksUI[i].getLinkId()); + } + if (this.__linksUI[i].getOutputNodeId() === nodeId) { + connectedLinks.push(this.__linksUI[i].getLinkId()); + } + } + return connectedLinks; + }, + + __getLink: function(id) { + for (let i = 0; i < this.__linksUI.length; i++) { + if (this.__linksUI[i].getLinkId() === id) { + return this.__linksUI[i]; + } + } + return null; + }, + + __removeNode: function(node) { + const removed = this.getWorkbenchModel().removeNode(node.getNodeModel()); + if (removed) { + this.__clearNode(node); + } + }, + + __removeAllNodes: function() { + while (this.__nodesUI.length > 0) { + this.__removeNode(this.__nodesUI[this.__nodesUI.length-1]); + } + }, + + __removeLink: function(link) { + let removed = false; + if (this.__currentModel.isContainer() && link.getOutputNodeId() === this.__currentModel.getNodeId()) { + let inputNode = this.getWorkbenchModel().getNodeModel(link.getInputNodeId()); + inputNode.setIsOutputNode(false); + + // Remove also dependencies from outter nodes + const cNodeId = inputNode.getNodeId(); + const allNodes = this.getWorkbenchModel().getNodeModels(true); + for (const nodeId in allNodes) { + let node = allNodes[nodeId]; + if (node.isInputNode(cNodeId) && !this.__currentModel.isInnerNode(node.getNodeId())) { + this.getWorkbenchModel().removeLink(cNodeId, nodeId); + } + } + + removed = true; + } else { + removed = this.getWorkbenchModel().removeLink(link.getInputNodeId(), link.getOutputNodeId()); + } + if (removed) { + this.__clearLink(link); + } + }, + + __removeAllLinks: function() { + while (this.__linksUI.length > 0) { + this.__removeLink(this.__linksUI[this.__linksUI.length-1]); + } + }, + + removeAll: function() { + this.__removeAllNodes(); + this.__removeAllLinks(); + }, + + __clearNode: function(node) { + if (this.__desktop.getChildren().includes(node)) { + this.__desktop.remove(node); + } + let index = this.__nodesUI.indexOf(node); + if (index > -1) { + this.__nodesUI.splice(index, 1); + } + }, + + __clearAllNodes: function() { + while (this.__nodesUI.length > 0) { + this.__clearNode(this.__nodesUI[this.__nodesUI.length-1]); + } + }, + + __clearLink: function(link) { + this.__svgWidget.removeCurve(link.getRepresentation()); + let index = this.__linksUI.indexOf(link); + if (index > -1) { + this.__linksUI.splice(index, 1); + } + }, + + __clearAllLinks: function() { + while (this.__linksUI.length > 0) { + this.__clearLink(this.__linksUI[this.__linksUI.length-1]); + } + }, + + clearAll: function() { + this.__clearAllNodes(); + this.__clearAllLinks(); + }, + + loadModel: function(model) { + this.clearAll(); + + this.__currentModel = model; + + if (model) { + const isContainer = model.isContainer(); + if (isContainer) { + this.__inputNodesLayout.setVisibility("visible"); + this.__clearInputNodeUIs(); + this.__createInputNodeUIs(model); + this.__outputNodesLayout.setVisibility("visible"); + this.__clearNodeExposedUIs(); + this.__createNodeExposedUIs(model); + } else { + this.__inputNodesLayout.setVisibility("excluded"); + this.__outputNodesLayout.setVisibility("excluded"); + } + qx.ui.core.queue.Visibility.flush(); + + let nodes = isContainer ? model.getInnerNodes() : model.getNodeModels(); + for (const nodeUuid in nodes) { + const nodeModel = nodes[nodeUuid]; + let node = this.__createNodeUI(nodeUuid); + this.__addNodeToWorkbench(node, nodeModel.getPosition()); + } + + for (const nodeUuid in nodes) { + const nodeModel = nodes[nodeUuid]; + const inputNodes = nodeModel.getInputNodes(); + for (let i=0; i b; @@ -109,18 +109,14 @@ qx.Class.define("qxapp.components.workbench.servicesCatalogue.ServicesCatalogue" __populateList: function() { let store = qxapp.data.Store.getInstance(); - [ - "builtInServicesRegistered", - "servicesRegistered", - "interactiveServicesRegistered" - ].forEach(event => { - store.addListener(event, e => { - this.__addNewData(e.getData()); - }, this); - }); - store.getBuiltInServicesAsync(); - store.getComputationalServices(); - store.getInteractiveServices(); + store.addListener("servicesRegistered", e => { + this.__addNewData(e.getData()); + }, this); + store.getServices(); + }, + + __getServiceNameInList: function(service) { + return (service.name + " " + service.version); }, __updateCompatibleList: function() { @@ -130,16 +126,18 @@ qx.Class.define("qxapp.components.workbench.servicesCatalogue.ServicesCatalogue" if (this.__contextPort.isInput === true) { let outputsMap = this.__allServices[i].outputs; for (let key in outputsMap) { - if (outputsMap[key].type === this.__contextPort.portType) { - newData.push(this.__allServices[i].name); + if (this.__areNodesCompatible(outputsMap[key], this.__contextPort)) { + const listName = this.__getServiceNameInList(this.__allServices[i]); + newData.push(listName); break; } } } else { let inputsMap = this.__allServices[i].inputs; for (let key in inputsMap) { - if (inputsMap[key].type === this.__contextPort.portType) { - newData.push(this.__allServices[i].name); + if (this.__areNodesCompatible(inputsMap[key], this.__contextPort)) { + const listName = this.__getServiceNameInList(this.__allServices[i]); + newData.push(listName); break; } } @@ -147,19 +145,27 @@ qx.Class.define("qxapp.components.workbench.servicesCatalogue.ServicesCatalogue" } } else { for (let i = 0; i < this.__allServices.length; i++) { - newData.push(this.__allServices[i].name); + const listName = this.__getServiceNameInList(this.__allServices[i]); + newData.push(listName); } } this.__setNewData(newData); }, + + __areNodesCompatible: function(topLevelPort1, topLevelPort2) { + return qxapp.data.Store.getInstance().areNodesCompatible(topLevelPort1, topLevelPort2); + }, + __setNewData: function(newData) { let filteredData = new qx.data.Array(newData); this.__controller.setModel(filteredData); }, __addNewData: function(newData) { - this.__allServices = this.__allServices.concat(newData); + for (const serviceKey in newData) { + this.__allServices.push(newData[serviceKey]); + } this.__updateCompatibleList(); }, @@ -171,7 +177,8 @@ qx.Class.define("qxapp.components.workbench.servicesCatalogue.ServicesCatalogue" let selection = this.__list.getSelection(); let selectedLabel = selection[0].getLabel(); for (let i = 0; i < this.__allServices.length; i++) { - if (selectedLabel === this.__allServices[i].name) { + const listName = this.__getServiceNameInList(this.__allServices[i]); + if (selectedLabel === listName) { const eData = { service: this.__allServices[i], contextNodeId: this.__contextNodeId, diff --git a/services/web/client/source/class/qxapp/components/form/renderer/PropForm.js b/services/web/client/source/class/qxapp/components/form/renderer/PropForm.js deleted file mode 100644 index 620b31a713a..00000000000 --- a/services/web/client/source/class/qxapp/components/form/renderer/PropForm.js +++ /dev/null @@ -1,93 +0,0 @@ -/* ************************************************************************ - Copyright: 2013 OETIKER+PARTNER AG - 2018 ITIS Foundation - License: MIT - Authors: Tobi Oetiker - Utf8Check: äöü -************************************************************************ */ - -/** - * A special renderer for AutoForms which includes notes below the section header - * widget and next to the individual form widgets. - */ -qx.Class.define("qxapp.components.form.renderer.PropForm", { - extend : qx.ui.form.renderer.Single, - /** - * create a page for the View Tab with the given title - * - * @param vizWidget {Widget} visualization widget to embedd - */ - construct: function(form) { - this.base(arguments, form); - let fl = this._getLayout(); - // have plenty of space for input, not for the labels - fl.setColumnFlex(0, 0); - fl.setColumnAlign(0, "left", "top"); - fl.setColumnFlex(1, 1); - fl.setColumnMinWidth(1, 130); - }, - - members: { - addItems: function(items, names, title, itemOptions, headerOptions) { - // add the header - if (title !== null) { - this._add( - this._createHeader(title), { - row: this._row, - column: 0, - colSpan: 3 - } - ); - this._row++; - } - - // add the items - for (let i = 0; i < items.length; i++) { - let item = items[i]; - let label = this._createLabel(names[i], item); - this._add(label, { - row: this._row, - column: 0 - }); - label.setBuddy(item); - this._add(item, { - row: this._row, - column: 1 - }); - if (itemOptions !== null && itemOptions[i] !== null && itemOptions[i].exposable) { - let exposeCtrl = new qx.ui.form.CheckBox().set({ - marginLeft: 20, - marginRight: 20 - }); - this._add(exposeCtrl, { - row: this._row, - column: 2 - }); - exposeCtrl.addListener("changeValue", function(e) { - item.setEnabled(!e.getData()); - }, this); - } - this._row++; - this._connectVisibility(item, label); - // store the names for translation - if (qx.core.Environment.get("qx.dynlocale")) { - this._names.push({ - name: names[i], - label: label, - item: items[i] - }); - } - } - }, - - getValues: function() { - return this._form.getData(); - }, - - enableProp: function(key, enable) { - if (this._form && this._form.getControl(key)) { - this._form.getControl(key).setEnabled(enable); - } - } - } -}); diff --git a/services/web/client/source/class/qxapp/components/workbench/NodeBase.js b/services/web/client/source/class/qxapp/components/workbench/NodeBase.js deleted file mode 100644 index 0401339d0fc..00000000000 --- a/services/web/client/source/class/qxapp/components/workbench/NodeBase.js +++ /dev/null @@ -1,359 +0,0 @@ -const nodeWidth = 240; -const portHeight = 16; - -qx.Class.define("qxapp.components.workbench.NodeBase", { - extend: qx.ui.window.Window, - - construct: function(nodeImageId, uuid) { - this.base(); - - this.set({ - appearance: "window-small-cap", - showMinimize: false, - showMaximize: false, - showClose: false, - showStatusbar: false, - resizable: false, - allowMaximize: false, - minWidth: nodeWidth, - maxWidth: nodeWidth, - // custom - nodeImageId: nodeImageId, - nodeId: uuid || qxapp.utils.Utils.uuidv4() - }); - }, - - properties: { - nodeId: { - check: "String", - nullable: false - }, - - nodeImageId: { - check: "String", - nullable: false - }, - - propsWidget: { - check: "qxapp.components.form.renderer.PropForm" - }, - - viewerButton: { - init: null, - check: "qx.ui.form.Button" - } - }, - - events: { - "LinkDragStart": "qx.event.type.Data", - "LinkDragOver": "qx.event.type.Data", - "LinkDrop": "qx.event.type.Data", - "LinkDragEnd": "qx.event.type.Data", - "NodeMoving": "qx.event.type.Event", - "ShowViewer": "qx.event.type.Data" - }, - - members: { - __inputPorts: null, - __outputPorts: null, - __inputPortsUI: null, - __outputPortsUI: null, - __progressLabel: null, - __settingsForm: null, - __progressBar: null, - __metaData: null, - - getMetaData: function() { - return this.__metaData; - }, - - createNodeLayout: function(nodeData) { - let nodeLayout = new qx.ui.layout.VBox(5, null, "separator-vertical"); - this.setLayout(nodeLayout); - - let inputsOutputsLayout = new qx.ui.container.Composite(new qx.ui.layout.HBox()); - this.add(inputsOutputsLayout, { - flex: 1 - }); - - let inputsBox = new qx.ui.layout.VBox(5); - this.__inputPortsUI = new qx.ui.container.Composite(inputsBox); - inputsOutputsLayout.add(this.__inputPortsUI, { - width: "50%" - }); - - let outputsBox = new qx.ui.layout.VBox(5); - this.__outputPortsUI = new qx.ui.container.Composite(outputsBox); - inputsOutputsLayout.add(this.__outputPortsUI, { - width: "50%" - }); - - - let progressBox = new qx.ui.container.Composite(new qx.ui.layout.Basic()); - progressBox.setMinWidth(nodeWidth-20); - - this.__progressBar = new qx.ui.indicator.ProgressBar(); - this.__progressBar.setWidth(nodeWidth-20); - progressBox.add(this.__progressBar, { - top: 0, - left: 0 - }); - - this.__progressLabel = new qx.ui.basic.Label("0%"); - progressBox.add(this.__progressLabel, { - top: 3, - left: nodeWidth/2 - 20 - }); - - this.add(progressBox); - - const nodeImageId = this.getNodeImageId(); - let store = qxapp.data.Store.getInstance(); - let metaData = store.getNodeMetaDataFromCache(nodeImageId); - if (metaData) { - this.__populateNode(metaData, nodeData); - } else { - console.error("Invalid ImageID - Not populating "+nodeImageId); - } - }, - - getInputPorts: function() { - return this.__inputPorts; - }, - getInputPort: function(portId) { - return this.__inputPorts[portId]; - }, - getOutputPorts: function() { - return this.__outputPorts; - }, - getOutputPort: function(portId) { - return this.__outputPorts[portId]; - }, - - getInputValues: function() { - return this.getPropsWidget().getValues(); - }, - - // override qx.ui.window.Window "move" event listener - _onMovePointerMove: function(e) { - this.base(arguments, e); - if (e.getPropagationStopped() === true) { - this.fireEvent("NodeMoving"); - } - }, - - __getCurrentBounds: function() { - let bounds = this.getBounds(); - let cel = this.getContentElement(); - if (cel) { - let domeEle = cel.getDomElement(); - if (domeEle) { - bounds.left = parseInt(domeEle.style.left); - bounds.top = parseInt(domeEle.style.top); - } - } - // NavigationBar height must be subtracted - // bounds.left = this.getContentLocation().left; - // bounds.top = this.getContentLocation().top; - return bounds; - }, - - __populateNode: function(metaData, nodeData) { - this.__metaData = metaData; - // this.__creteSettings(metaData.inputs); - this.setCaption(metaData.name + " " + metaData.version); - this.__createViewerButton(); - this.__outputPorts = {}; - this.__inputPorts = {}; - this.__createPorts("Input", metaData.inputs); - this.__createPorts("Output", metaData.outputs); - this.__addSettings(metaData.inputs); - if (nodeData) { - this.__settingsForm.setData(nodeData.inputs); - } - }, - - __addSettings: function(inputs) { - if (inputs === null) { - return; - } - let form = this.__settingsForm = new qxapp.components.form.Auto(inputs); - // FIXME - // this.__settingsForm.addListener("changeData", function(e) { - // let settingsForm = e.getData(); - // for (var settingKey in settingsForm) { - // if (this.__metaData.inputs) { - // for (let i=0; i { - let x = ports[a].displayOrder; - let y = ports[b].displayOrder; - if (x > y) { - return 1; - } - if (x < y) { - return -1; - } - return 0; - }) - .forEach(portId => { - switch (type) { - case "Output": - this.__addOutputPort(portId, ports[portId]); - break; - case "Input": - this.__addInputPort(portId, ports[portId]); - break; - } - }); - }, - __addInputPort: function(portId, inputData) { - let label = this.__createPort(true, portId, inputData); - this.getInputPorts()[portId] = label; - this.__inputPortsUI.add(label.ui); - }, - - __addOutputPort: function(portId, outputData) { - let label = this.__createPort(false, portId, outputData); - this.getOutputPorts()[portId]=label; - this.__outputPortsUI.add(label.ui); - }, - __createPort: function(isInput, portId, portData) { - let label = {}; - label.portId = portId; - label.isInput = isInput; - label.portType = portData.type; - let iconSize = (portHeight-4).toString(); - let icon = "@FontAwesome5Solid/edit/" + iconSize; - if (portData.type.match(/^data:/)) { - icon = "@FontAwesome5Solid/file/" + (portHeight-2).toString(); - } - const alignX = (isInput) ? "left" : "right"; - label.ui = new qx.ui.basic.Atom(portData.label, icon).set({ - height: portHeight, - draggable: true, - droppable: true, - iconPosition: alignX, - alignX: alignX, - allowGrowX: false - }); - label.ui.portId = portId; - - var tooltip = new qx.ui.tooltip.ToolTip(portData.description, icon); - tooltip.setShowTimeout(50); - label.ui.setToolTip(tooltip); - - [ - ["dragstart", "LinkDragStart"], - ["dragover", "LinkDragOver"], - ["drop", "LinkDrop"], - ["dragend", "LinkDragEnd"] - ].forEach(eventPair => { - label.ui.addListener(eventPair[0], e => { - const eData = { - event: e, - nodeId: this.getNodeId(), - portId: portId, - isInput: isInput, - dataType: portData.type - }; - this.fireDataEvent(eventPair[1], eData); - }, this); - }, this); - return label; - }, - - getLinkPoint: function(port) { - const nodeBounds = this.__getCurrentBounds(); - let x = nodeBounds.left; - if (port.isInput === false) { - x += nodeBounds.width; - } - const captionHeight = this.__childControls.captionbar.getBounds().height; - const inputOutputs = this.getChildren()[0]; - const inputPorts = inputOutputs.getChildren()[0].getChildren(); - const outputPorts = inputOutputs.getChildren()[1].getChildren(); - const ports = inputPorts.concat(outputPorts); - let portBounds; - for (let i=0; i { - // Will be called only the first time Svg lib is loaded - this.__loadProject(workbenchData); - }); - } - - this.__desktop.add(this.__svgWidget, { - left: 0, - top: 0, - right: 0, - bottom: 0 - }); - - this.__desktop.addListener("click", function(e) { - this.__selectedItemChanged(null); - }, this); - - this.__desktop.addListener("changeActiveWindow", function(e) { - let winEmitting = e.getData(); - if (winEmitting && winEmitting.isActive() && winEmitting.classname.includes("workbench.Node")) { - this.__selectedItemChanged(winEmitting.getNodeId()); - } else { - this.__selectedItemChanged(null); - } - }, this); - // TODO how about making the LoggerView a singleton then it could be accessed from anywhere - this.__logger = new qxapp.components.workbench.logger.LoggerView(); - this.__desktop.add(this.__logger); - - this.__nodes = []; - this.__nodeMap = {}; - this.__links = []; - - let loggerButton = this.__getShowLoggerButton(); - this.add(loggerButton, { - left: 20, - bottom: 20 - }); - - let buttonContainer = new qx.ui.container.Composite(new qx.ui.layout.HBox(BUTTON_SPACING)); - this.add(buttonContainer, { - bottom: 20, - right: 20 - }); - [ - this.__getPlusButton(), - this.__getRemoveButton(), - this.__getPlayButton(), - this.__getStopButton() - ].forEach(widget => { - buttonContainer.add(widget); - }); - - this.setCanStart(true); - - this.addListener("dblclick", function(pointerEvent) { - // FIXME: - const navBarHeight = 50; - let x = pointerEvent.getViewportLeft() - this.getBounds().left; - let y = pointerEvent.getViewportTop() - navBarHeight; - - let srvCat = new qxapp.components.workbench.servicesCatalogue.ServicesCatalogue(); - srvCat.moveTo(x, y); - srvCat.open(); - let pos = { - x: x, - y: y - }; - srvCat.addListener("AddService", function(e) { - this.__addServiceFromCatalogue(e, pos); - }, this); - }, this); - }, - - events: { - "NodeDoubleClicked": "qx.event.type.Data" - }, - - properties: { - canStart: { - nullable: false, - init: true, - check: "Boolean", - apply : "__applyCanStart" - } - }, - - members: { - __nodes: null, - __nodeMap: null, - __links: null, - __desktop: null, - __svgWidget: null, - __logger: null, - __tempLinkNodeId: null, - __tempLinkPortId: null, - __tempLinkRepr: null, - __pointerPosX: null, - __pointerPosY: null, - __selectedItemId: null, - __playButton: null, - __stopButton: null, - - __getShowLoggerButton: function() { - const icon = "@FontAwesome5Solid/list-alt/32"; - let loggerButton = new qx.ui.form.Button(null, icon); - loggerButton.set({ - width: BUTTON_SIZE, - height: BUTTON_SIZE - }); - loggerButton.addListener("execute", function() { - const bounds = loggerButton.getBounds(); - loggerButton.hide(); - this.__logger.moveTo(bounds.left, bounds.top+bounds.height - this.__logger.getHeight()); - this.__logger.open(); - this.__logger.addListenerOnce("close", function() { - loggerButton.show(); - }, this); - }, this); - return loggerButton; - }, - - __getPlusButton: function() { - const icon = "@FontAwesome5Solid/plus/32"; // qxapp.dev.Placeholders.getIcon("fa-plus", 32); - let plusButton = new qx.ui.form.Button(null, icon); - plusButton.set({ - width: BUTTON_SIZE, - height: BUTTON_SIZE - }); - plusButton.addListener("execute", function() { - let srvCat = new qxapp.components.workbench.servicesCatalogue.ServicesCatalogue(); - srvCat.moveTo(200, 200); - srvCat.open(); - srvCat.addListener("AddService", function(e) { - this.__addServiceFromCatalogue(e); - }, this); - }, this); - return plusButton; - }, - - __getPlayButton: function() { - const icon = "@FontAwesome5Solid/play/32"; - let playButton = this.__playButton = new qx.ui.form.Button(null, icon); - playButton.set({ - width: BUTTON_SIZE, - height: BUTTON_SIZE - }); - - playButton.addListener("execute", function() { - if (this.getCanStart()) { - this.__startPipeline(); - } else { - this.__logger.info("Can not start pipeline"); - } - }, this); - - return playButton; - }, - - __getStopButton: function() { - const icon = "@FontAwesome5Solid/stop-circle/32"; - let stopButton = this.__stopButton = new qx.ui.form.Button(null, icon); - stopButton.set({ - width: BUTTON_SIZE, - height: BUTTON_SIZE - }); - - stopButton.addListener("execute", function() { - this.__stopPipeline(); - }, this); - return stopButton; - }, - - __applyCanStart: function(value, old) { - if (value) { - this.__playButton.setVisibility("visible"); - this.__stopButton.setVisibility("excluded"); - } else { - this.__playButton.setVisibility("excluded"); - this.__stopButton.setVisibility("visible"); - } - }, - - __getRemoveButton: function() { - const icon = "@FontAwesome5Solid/trash/32"; - let removeButton = new qx.ui.form.Button(null, icon); - removeButton.set({ - width: BUTTON_SIZE, - height: BUTTON_SIZE - }); - removeButton.addListener("execute", function() { - if (this.__selectedItemId && this.__isSelectedItemALink(this.__selectedItemId)) { - this.__removeLink(this.__getLink(this.__selectedItemId)); - this.__selectedItemId = null; - } else { - this.__removeSelectedNode(); - } - }, this); - return removeButton; - }, - - __addServiceFromCatalogue: function(e, pos) { - let data = e.getData(); - let metaData = data.service; - console.log("metaData", metaData); - const nodeImageId = metaData.key + "-" + metaData.version; - let nodeAId = data.contextNodeId; - let portA = data.contextPort; - - let nodeB = this.__createNode(nodeImageId, null); - this.__addNodeToWorkbench(nodeB, pos); - - if (nodeAId !== null && portA !== null) { - let nodeBId = nodeB.getNodeId(); - let portB = this.__findCompatiblePort(nodeB, portA); - // swap node-ports to have node1 as input and node2 as output - if (portA.isInput) { - [nodeAId, portA, nodeBId, portB] = [nodeBId, portB, nodeAId, portA]; - } - this.__addLink({ - nodeUuid: nodeAId, - output: portA.portId - }, { - nodeUuid: nodeBId, - input: portB.portId - }); - } - }, - - __createWindowForBuiltInService: function(widget, width, height, caption) { - let serviceWindow = new qx.ui.window.Window(); - serviceWindow.set({ - showMinimize: false, - showStatusbar: false, - width: width, - height: height, - minWidth: 400, - minHeight: 400, - modal: true, - caption: caption, - layout: new qx.ui.layout.Canvas() - }); - - serviceWindow.add(widget, { - left: 0, - top: 0, - right: 0, - bottom: 0 - }); - - serviceWindow.moveTo(100, 100); - - return serviceWindow; - }, - - __addNodeToWorkbench: function(node, position) { - if (position === undefined || position === null) { - let farthestRight = 0; - for (let i=0; i < this.__nodes.length; i++) { - let boundPos = this.__nodes[i].getBounds(); - let rightPos = boundPos.left + boundPos.width; - if (farthestRight < rightPos) { - farthestRight = rightPos; - } - } - node.moveTo(50 + farthestRight, 200); - } else { - node.moveTo(position.x, position.y); - } - this.addWindowToDesktop(node); - this.__nodes.push(node); - - node.addListener("NodeMoving", function() { - this.__updateLinks(node); - }, this); - - node.addListener("appear", function() { - this.__updateLinks(node); - }, this); - - node.addListener("dblclick", function(e) { - if (node.getMetaData().key.includes("FileManager")) { - const width = 800; - const height = 600; - let fileManager = new qxapp.components.widgets.FileManager(); - let fileManagerWindow = this.__createWindowForBuiltInService(fileManager, width, height, "File Manager"); - fileManager.addListener("ItemSelected", function(data) { - const itemPath = data.getData().itemPath; - const splitted = itemPath.split("/"); - const itemName = splitted[splitted.length-1]; - const isDirectory = data.getData().isDirectory; - const activePort = isDirectory ? "outDir" : "outFile"; - const inactivePort = isDirectory ? "outFile" : "outDir"; - let metadata = node.getMetaData(); - metadata.outputs[activePort].value = { - store: "s3-z43", - path: itemPath - }; - metadata.outputs[inactivePort].value = null; - node.getOutputPort(activePort).ui.setLabel(itemName); - node.getOutputPort(activePort).ui.getToolTip().setLabel(itemName); - node.getOutputPort(inactivePort).ui.setLabel(""); - node.getOutputPort(inactivePort).ui.getToolTip().setLabel(""); - node.setProgress(100); - fileManagerWindow.close(); - }, this); - - fileManagerWindow.moveTo(100, 100); - fileManagerWindow.open(); - } else { - this.fireDataEvent("NodeDoubleClicked", node); - } - e.stopPropagation(); - }, this); - - qx.ui.core.queue.Layout.flush(); - }, - - __createNode: function(nodeImageId, uuid, nodeData) { - let nodeBase = new qxapp.components.workbench.NodeBase(nodeImageId, uuid); - nodeBase.createNodeLayout(nodeData); - - const evType = "pointermove"; - nodeBase.addListener("LinkDragStart", function(e) { - let data = e.getData(); - let event = data.event; - let dragNodeId = data.nodeId; - let dragIsInput = data.isInput; - let dragPortId = data.portId; - - // Register supported actions - event.addAction("move"); - - // Register supported types - event.addType("osparc-metaData"); - let dragData = { - dragNodeId: dragNodeId, - dragIsInput: dragIsInput, - dragPortId: dragPortId - }; - event.addData("osparc-metaData", dragData); - - this.__tempLinkNodeId = dragData.dragNodeId; - this.__tempLinkIsInput = dragData.dragIsInput; - this.__tempLinkPortId = dragData.dragPortId; - qx.bom.Element.addListener( - this.__desktop, - evType, - this.__startTempLink, - this - ); - }, this); - - nodeBase.addListener("LinkDragOver", function(e) { - let data = e.getData(); - let event = data.event; - let dropNodeId = data.nodeId; - let dropIsInput = data.isInput; - let dropPortId = data.portId; - - let compatible = false; - if (event.supportsType("osparc-metaData")) { - const dragNodeId = event.getData("osparc-metaData").dragNodeId; - const dragIsInput = event.getData("osparc-metaData").dragIsInput; - const dragPortId = event.getData("osparc-metaData").dragPortId; - const dragNode = this.__getNode(dragNodeId); - const dropNode = this.__getNode(dropNodeId); - const dragPortTarget = dragIsInput ? dragNode.getInputPort(dragPortId) : dragNode.getOutputPort(dragPortId); - const dropPortTarget = dropIsInput ? dropNode.getInputPort(dropPortId) : dropNode.getOutputPort(dropPortId); - compatible = this.__arePortsCompatible(dragPortTarget, dropPortTarget); - } - - if (!compatible) { - event.preventDefault(); - } - }, this); - - nodeBase.addListener("LinkDrop", function(e) { - let data = e.getData(); - let event = data.event; - let dropNodeId = data.nodeId; - let dropIsInput = data.isInput; - let dropPortId = data.portId; - - if (event.supportsType("osparc-metaData")) { - let dragNodeId = event.getData("osparc-metaData").dragNodeId; - let dragIsInput = event.getData("osparc-metaData").dragIsInput; - let dragPortId = event.getData("osparc-metaData").dragPortId; - - let nodeAId = dropIsInput ? dragNodeId : dropNodeId; - let nodeAPortId = dropIsInput ? dragPortId : dropPortId; - let nodeBId = dragIsInput ? dragNodeId : dropNodeId; - let nodeBPortId = dragIsInput ? dragPortId : dropPortId; - - this.__addLink({ - nodeUuid: nodeAId, - output: nodeAPortId - }, { - nodeUuid: nodeBId, - input: nodeBPortId - }); - this.__removeTempLink(); - qx.bom.Element.removeListener( - this.__desktop, - evType, - this.__startTempLink, - this - ); - } - }, this); - - nodeBase.addListener("LinkDragEnd", function(e) { - let data = e.getData(); - // let event = data.event"]; - let dragNodeId = data.nodeId; - let dragPortId = data.portId; - - let posX = this.__pointerPosX; - let posY = this.__pointerPosY; - if (this.__tempLinkNodeId === dragNodeId && this.__tempLinkPortId === dragPortId) { - let srvCat = new qxapp.components.workbench.servicesCatalogue.ServicesCatalogue(); - if (this.__tempLinkIsInput === true) { - srvCat.setContext(dragNodeId, this.__getNode(dragNodeId).getInputPort(dragPortId)); - } else { - srvCat.setContext(dragNodeId, this.__getNode(dragNodeId).getOutputPort(dragPortId)); - } - srvCat.moveTo(posX, posY); - srvCat.open(); - let pos = { - x: posX, - y: posY - }; - srvCat.addListener("AddService", function(ev) { - this.__addServiceFromCatalogue(ev, pos); - }, this); - srvCat.addListener("close", function(ev) { - this.__removeTempLink(); - }, this); - } - qx.bom.Element.removeListener( - this.__desktop, - evType, - this.__startTempLink, - this - ); - }, this); - - return nodeBase; - }, - - __removeSelectedNode: function() { - for (let i=0; i { - let link = this.__getLink(linkId); - if (link) { - let node1 = this.__getNode(link.getInputNodeId()); - let port1 = node1.getOutputPort(link.getInputPortId()); - let node2 = this.__getNode(link.getOutputNodeId()); - let port2 = node2.getInputPort(link.getOutputPortId()); - const pointList = this.__getLinkPoints(node1, port1, node2, port2); - const x1 = pointList[0][0]; - const y1 = pointList[0][1]; - const x2 = pointList[1][0]; - const y2 = pointList[1][1]; - this.__svgWidget.updateCurve(link.getRepresentation(), x1, y1, x2, y2); - } - }); - }, - - __startTempLink: function(pointerEvent) { - if (this.__tempLinkNodeId === null || this.__tempLinkPortId === null) { - return; - } - let node = this.__getNode(this.__tempLinkNodeId); - if (node === null) { - return; - } - let port; - if (this.__tempLinkIsInput) { - port = node.getInputPort(this.__tempLinkPortId); - } else { - port = node.getOutputPort(this.__tempLinkPortId); - } - if (port === null) { - return; - } - - let x1; - let y1; - let x2; - let y2; - const portPos = node.getLinkPoint(port); - // FIXME: - const navBarHeight = 50; - this.__pointerPosX = pointerEvent.getViewportLeft() - this.getBounds().left; - this.__pointerPosY = pointerEvent.getViewportTop() - navBarHeight; - - if (port.isInput) { - x1 = this.__pointerPosX; - y1 = this.__pointerPosY; - x2 = portPos[0]; - y2 = portPos[1]; - } else { - x1 = portPos[0]; - y1 = portPos[1]; - x2 = this.__pointerPosX; - y2 = this.__pointerPosY; - } - - if (this.__tempLinkRepr === null) { - this.__tempLinkRepr = this.__svgWidget.drawCurve(x1, y1, x2, y2); - } else { - this.__svgWidget.updateCurve(this.__tempLinkRepr, x1, y1, x2, y2); - } - }, - - __removeTempLink: function() { - if (this.__tempLinkRepr !== null) { - this.__svgWidget.removeCurve(this.__tempLinkRepr); - } - this.__tempLinkRepr = null; - this.__tempLinkNodeId = null; - this.__tempLinkPortId = null; - this.__pointerPosX = null; - this.__pointerPosY = null; - }, - - __getLinkPoints: function(node1, port1, node2, port2) { - let p1 = null; - let p2 = null; - // swap node-ports to have node1 as input and node2 as output - if (port1.isInput) { - [node1, port1, node2, port2] = [node2, port2, node1, port1]; - } - p1 = node1.getLinkPoint(port1); - p2 = node2.getLinkPoint(port2); - // hack to place the arrow-head properly - p2[0] -= 6; - return [p1, p2]; - }, - - __getNode: function(id) { - for (let i = 0; i < this.__nodes.length; i++) { - if (this.__nodes[i].getNodeId() === id) { - return this.__nodes[i]; - } - } - return null; - }, - - __getConnectedLinks: function(nodeId) { - let connectedLinks = []; - for (let i = 0; i < this.__links.length; i++) { - if (this.__links[i].getInputNodeId() === nodeId) { - connectedLinks.push(this.__links[i].getLinkId()); - } - if (this.__links[i].getOutputNodeId() === nodeId) { - connectedLinks.push(this.__links[i].getLinkId()); - } - } - return connectedLinks; - }, - - __getLink: function(id) { - for (let i = 0; i < this.__links.length; i++) { - if (this.__links[i].getLinkId() === id) { - return this.__links[i]; - } - } - return null; - }, - - __removeNode: function(node) { - if (node.getMetaData().type == "dynamic") { - const slotName = "stopDynamic"; - let socket = qxapp.wrappers.WebSocket.getInstance(); - let data = { - nodeId: node.getNodeId() - }; - socket.emit(slotName, data); - } - - this.__desktop.remove(node); - let index = this.__nodes.indexOf(node); - if (index > -1) { - this.__nodes.splice(index, 1); - } - }, - - __removeAllNodes: function() { - while (this.__nodes.length > 0) { - this.__removeNode(this.__nodes[this.__nodes.length-1]); - } - }, - - __removeLink: function(link) { - let node2 = this.__getNode(link.getOutputNodeId()); - if (node2) { - node2.getPropsWidget().enableProp(link.getOutputPortId(), true); - } - - this.__svgWidget.removeCurve(link.getRepresentation()); - let index = this.__links.indexOf(link); - if (index > -1) { - this.__links.splice(index, 1); - } - }, - - __removeAllLinks: function() { - while (this.__links.length > 0) { - this.__removeLink(this.__links[this.__links.length-1]); - } - }, - - removeAll: function() { - this.__removeAllNodes(); - this.__removeAllLinks(); - }, - - __getInputPortLinked: function(nodeId, inputPortId) { - for (let i = 0; i < this.__links.length; i++) { - const link = this.__links[i]; - if (link.getOutputNodeId() === nodeId && link.getOutputPortId() === inputPortId) { - return { - nodeUuid: link.getInputNodeId(), - output: link.getInputPortId() - }; - } - } - return null; - }, - - __loadProject: function(workbenchData) { - for (let nodeUuid in workbenchData) { - // TODO: SAN: What is the difference between node data and node meta data?? - let nodeData = workbenchData[nodeUuid]; - const nodeImageId = nodeData.key + "-" + nodeData.version; - let node = this.__createNode(nodeImageId, nodeUuid, nodeData); - this.__addNodeToWorkbench(node, nodeData.position); - } - for (let nodeUuid in workbenchData) { - let nodeData = workbenchData[nodeUuid]; - if (nodeData.inputs) { - for (let prop in nodeData.inputs) { - let link = nodeData.inputs[prop]; - if (typeof link == "object" && link.nodeUuid) { - this.__addLink({ - nodeUuid: link.nodeUuid, - output: link.output - }, { - nodeUuid: nodeUuid, - input: prop - }); - } - } - } - } - }, - - __serializePipeline: function() { - if (this.__projectId === null || this.__projectId === undefined) { - this.__projectId = qxapp.utils.Utils.uuidv4(); - } - let pipeline = { - projectId: this.__projectId, - workbench: {} - }; - for (let i = 0; i < this.__nodes.length; i++) { - const node = this.__nodes[i]; - const nodeData = node.getMetaData(); - let cNode = pipeline.workbench[node.getNodeId()] = { - key: nodeData.key, - version: nodeData.version, - inputs: node.getInputValues(), - outputs: {} - }; - for (let key in node.getInputPorts()) { - const linkPort = this.__getInputPortLinked(node.getNodeId(), key); - if (linkPort) { - cNode.inputs[key] = linkPort; - } - } - for (let key in nodeData.outputs) { - const outputPort = nodeData.outputs[key]; - if ("value" in outputPort) { - cNode.outputs[key] = outputPort.value; - } - } - } - return pipeline; - }, - - addWindowToDesktop: function(node) { - this.__desktop.add(node); - node.open(); - }, - - __startPipeline: function() { - // ui start pipeline - // this.__clearProgressData(); - - let socket = qxapp.wrappers.WebSocket.getInstance(); - - // callback for incoming logs - if (!socket.slotExists("logger")) { - socket.on("logger", function(data) { - let d = JSON.parse(data); - let node = d["Node"]; - let msg = d["Message"]; - this.__updateLogger(node, msg); - }, this); - } - socket.emit("logger"); - - // callback for incoming progress - if (!socket.slotExists("progress")) { - socket.on("progress", function(data) { - console.log("progress", data); - let d = JSON.parse(data); - let node = d["Node"]; - let progress = 100*Number.parseFloat(d["Progress"]).toFixed(4); - this.updateProgress(node, progress); - }, this); - } - - // post pipeline - this.__pipelineId = null; - let currentPipeline = this.__serializePipeline(); - console.log("pipeline:", currentPipeline); - let req = new qx.io.request.Xhr(); - let data = {}; - data = currentPipeline; - data["pipeline_mockup_id"] = qxapp.utils.Utils.uuidv4(); - req.set({ - url: "/start_pipeline", - method: "POST", - requestData: qx.util.Serializer.toJson(data) - }); - req.addListener("success", this.__onPipelinesubmitted, this); - req.addListener("error", function(e) { - this.setCanStart(true); - this.__logger.error("Workbench", "Error submitting pipeline"); - }, this); - req.addListener("fail", function(e) { - this.setCanStart(true); - this.__logger.error("Workbench", "Failed submitting pipeline"); - }, this); - req.send(); - - this.__logger.info("Workbench", "Starting pipeline"); - }, - - __onPipelinesubmitted: function(e) { - let req = e.getTarget(); - console.debug("Everything went fine!!"); - console.debug("status : ", req.getStatus()); - console.debug("phase : ", req.getPhase()); - console.debug("response: ", req.getResponse()); - - const pipelineId = req.getResponse().pipeline_id; - this.__logger.debug("Workbench", "Pipeline ID " + pipelineId); - const notGood = [null, undefined, -1]; - if (notGood.includes(pipelineId)) { - this.setCanStart(true); - this.__pipelineId = null; - this.__logger.error("Workbench", "Submition failed"); - } else { - this.setCanStart(false); - this.__pipelineId = pipelineId; - this.__logger.info("Workbench", "Pipeline started"); - } - }, - - __stopPipeline: function() { - let req = new qx.io.request.Xhr(); - let data = {}; - data["pipeline_id"] = this.__pipelineId; - req.set({ - url: "/stop_pipeline", - method: "POST", - requestData: qx.util.Serializer.toJson(data) - }); - req.addListener("success", this.__onPipelineStopped, this); - req.addListener("error", function(e) { - this.setCanStart(false); - this.__logger.error("Workbench", "Error stopping pipeline"); - }, this); - req.addListener("fail", function(e) { - this.setCanStart(false); - this.__logger.error("Workbench", "Failed stopping pipeline"); - }, this); - // req.send(); - - // temporary solution - this.setCanStart(true); - - this.__logger.info("Workbench", "Stopping pipeline. Not yet implemented"); - }, - - __onPipelineStopped: function(e) { - this.__clearProgressData(); - - this.setCanStart(true); - }, - - __updateLogger: function(nodeId, msg) { - let node = this.__getNode(nodeId); - if (node) { - this.__logger.info(node.getCaption(), msg); - } - }, - - __clearProgressData: function() { - for (let i = 0; i < this.__nodes.length; i++) { - this.__nodes[i].setProgress(0); - } - }, - - updateProgress: function(nodeId, progress) { - let node = this.__getNode(nodeId); - if (node) { - node.setProgress(progress); - } - }, - - __selectedItemChanged: function(newID) { - if (newID === this.__selectedItemId) { - return; - } - - let oldId = this.__selectedItemId; - if (oldId) { - if (this.__isSelectedItemALink(oldId)) { - let unselectedLink = this.__getLink(oldId); - const unselectedColor = qxapp.theme.Color.colors["workbench-link-active"]; - this.__svgWidget.updateColor(unselectedLink.getRepresentation(), unselectedColor); - } - } - - this.__selectedItemId = newID; - if (this.__isSelectedItemALink(newID)) { - let selectedLink = this.__getLink(newID); - const selectedColor = qxapp.theme.Color.colors["workbench-link-selected"]; - this.__svgWidget.updateColor(selectedLink.getRepresentation(), selectedColor); - } - }, - - __isSelectedItemALink: function() { - return Boolean(this.__getLink(this.__selectedItemId)); - } - } -}); diff --git a/services/web/client/source/class/qxapp/data/Store.js b/services/web/client/source/class/qxapp/data/Store.js index be44af57a92..65a88d1255d 100644 --- a/services/web/client/source/class/qxapp/data/Store.js +++ b/services/web/client/source/class/qxapp/data/Store.js @@ -4,9 +4,7 @@ qx.Class.define("qxapp.data.Store", { type : "singleton", events: { - "builtInServicesRegistered": "qx.event.type.Event", - "servicesRegistered": "qx.event.type.Event", - "interactiveServicesRegistered": "qx.event.type.Event" + "servicesRegistered": "qx.event.type.Event" }, statics: { @@ -23,54 +21,339 @@ qx.Class.define("qxapp.data.Store", { }, members: { - __servicesCacheBuiltIn: null, - __servicesCacheComputational: null, - __servicesCacheInteractive: null, + __servicesCache: null, - getServices: function() { - let services = {}; - services = Object.assign(services, this.getBuiltInServices()); - services = Object.assign(services, qxapp.dev.fake.Data.getNodeMap()); - return services; + __getMimeType: function(type) { + let match = type.match(/^data:([^/\s]+\/[^/;\s])/); + if (match) { + return match[1]; + } + return null; + }, + + __matchPortType: function(typeA, typeB) { + if (typeA === typeB) { + return true; + } + let mtA = this.__getMimeType(typeA); + let mtB = this.__getMimeType(typeB); + return mtA && mtB && + new qxapp.data.MimeType(mtA).match(new qxapp.data.MimeType(mtB)); + }, + + areNodesCompatible: function(topLevelPort1, topLevelPort2) { + console.log("areNodesCompatible", topLevelPort1, topLevelPort2); + return topLevelPort1.isInput !== topLevelPort2.isInput; + }, + + arePortsCompatible: function(node1, port1, node2, port2) { + console.log("arePortsCompatible", node1, port1, node2, port2); + return true; + /* + return this.__matchPortType(port1.portType, port2.portType) && + (port1.isInput !== port2.isInput); + */ }, getProjectList: function() { return qxapp.dev.fake.Data.getProjectList(); }, - getNodeMetaData: function(nodeImageId) { - let metaData = this.getServices()[nodeImageId]; - if (metaData === undefined) { - metaData = this.getBuiltInServices()[nodeImageId]; + getProjectData: function(projectUuid) { + return qxapp.dev.fake.Data.getProjectData(projectUuid); + }, + + getNodeMetaData: function(key, version) { + let metaData = {}; + if (key && version) { + const nodeImageId = key + "-" + version; + if (nodeImageId in this.__servicesCache) { + return this.__servicesCache[nodeImageId]; + } + metaData = this.getFakeServices()[nodeImageId]; + if (metaData === undefined) { + metaData = this.getBuiltInServices()[nodeImageId]; + } } return metaData; }, - getNodeMetaDataFromCache: function(nodeImageId) { - let metadata = this.getNodeMetaData(nodeImageId); - if (metadata) { - return metadata; - } - let services = this.__servicesCacheBuiltIn.concat(this.__servicesCacheComputational); - services = services.concat(this.__servicesCacheInteractive); - for (let i=0; i { let requ = e.getTarget(); const { data, - status + error } = requ.getResponse(); - if (status >= 200 && status <= 299) { - const listOfRepositories = data; - console.log("listOfServices", listOfRepositories); - let services = []; - for (const key of Object.keys(listOfRepositories)) { - const repoData = listOfRepositories[key]; - let newMetaData = qxapp.data.Converters.registryToMetaData(repoData); - services.push(newMetaData); - } - this.__servicesCacheComputational = services; - this.fireDataEvent("servicesRegistered", services); - } else { - // error - console.error("Error retrieving services: ", data); + if (error) { + console.error("Error retrieving services: ", error); + return; + } + const listOfRepositories = data; + let services = Object.assign({}, this.getBuiltInServices()); + for (const key in listOfRepositories) { + const repoData = listOfRepositories[key]; + const nodeImageId = repoData.key + "-" + repoData.version; + services[nodeImageId] = repoData; + } + if (this.__servicesCache === null) { + this.__servicesCache = {}; } + this.__servicesCache = Object.assign(this.__servicesCache, services); + this.fireDataEvent("servicesRegistered", services); }, this); - req.send(); - }, - getInteractiveServices: function() { - let socket = qxapp.wrappers.WebSocket.getInstance(); - socket.removeSlot("getInteractiveServices"); - socket.on("getInteractiveServices", function(e) { + req.addListener("fail", e => { + let requ = e.getTarget(); const { data, - status - } = e; - if (status >= 200 && status <= 299) { - let listOfInteractiveServices = data; - console.log("listOfInteractiveServices", listOfInteractiveServices); - let services = []; - for (const key of Object.keys(listOfInteractiveServices)) { - const repoData = listOfInteractiveServices[key]; - let newMetaData = qxapp.data.Converters.registryToMetaData(repoData); - services.push(newMetaData); - } - this.__servicesCacheInteractive = services; - this.fireDataEvent("interactiveServicesRegistered", services); - } else { - // error - console.error("Error retrieving services: ", data); + error + } = requ.getResponse(); + console.log("getServices failed", data, error); + let services = this.getFakeServices(); + if (this.__servicesCache === null) { + this.__servicesCache = {}; } + this.__servicesCache = Object.assign(this.__servicesCache, services); + this.fireDataEvent("servicesRegistered", services); }, this); - socket.emit("getInteractiveServices"); + req.send(); } } }); diff --git a/services/web/client/source/class/qxapp/data/model/NodeModel.js b/services/web/client/source/class/qxapp/data/model/NodeModel.js new file mode 100644 index 00000000000..1f751d914aa --- /dev/null +++ b/services/web/client/source/class/qxapp/data/model/NodeModel.js @@ -0,0 +1,312 @@ +qx.Class.define("qxapp.data.model.NodeModel", { + extend: qx.core.Object, + + construct: function(key, version, uuid) { + this.base(arguments); + + this.__metaData = {}; + this.__innerNodes = {}; + this.__inputNodes = []; + this.__outputs = {}; + + this.set({ + nodeId: uuid || qxapp.utils.Utils.uuidv4() + }); + + if (key && version) { + // not container + this.set({ + nodeImageId: key + "-" + version + }); + let store = qxapp.data.Store.getInstance(); + let metaData = this.__metaData = store.getNodeMetaData(key, version); + if (metaData) { + this.__startInteractiveNode(); + if (metaData.inputs) { + this.__addSettings(metaData.inputs); + } + if (metaData.outputs) { + this.__addOutputs(metaData.outputs); + } + if (metaData.name) { + this.setLabel(metaData.name); + } + } + } + }, + + properties: { + nodeId: { + check: "String", + nullable: false + }, + + nodeImageId: { + check: "String", + init: null, + nullable: true + }, + + label: { + check: "String", + nullable: true + }, + + propsWidget: { + check: "qxapp.component.form.renderer.PropForm" + }, + + parentNodeId: { + check: "String", + nullable: true + }, + + isOutputNode: { + check: "Boolean", + init: false, + nullable: false + }, + + serviceUrl: { + check: "String", + nullable: true + }, + + viewerButton: { + check: "qx.ui.form.Button", + init: null + } + }, + + events: { + "ShowInLogger": "qx.event.type.Event" + }, + + members: { + __metaData: null, + __innerNodes: null, + __inputNodes: null, + __settingsForm: null, + __outputs: null, + __posX: null, + __posY: null, + + isContainer: function() { + return (this.getNodeImageId() === null); + }, + + getMetaData: function() { + return this.__metaData; + }, + + getInputValues: function() { + if (this.isPropertyInitialized("propsWidget")) { + return this.getPropsWidget().getValues(); + } + return {}; + }, + + getOutputs: function() { + return this.__outputs; + }, + + getOutputValues: function() { + let output = {}; + for (const outputId in this.__outputs) { + if ("value" in this.__outputs[outputId]) { + output[outputId] = this.__outputs[outputId].value; + } + } + return output; + }, + + getInnerNodes: function(recursive = false) { + let innerNodes = Object.assign({}, this.__innerNodes); + if (recursive) { + for (const innerNodeId in this.__innerNodes) { + let myInnerNodes = this.__innerNodes[innerNodeId].getInnerNodes(true); + innerNodes = Object.assign(innerNodes, myInnerNodes); + } + } + return innerNodes; + }, + + addInnerNode: function(innerNodeId, innerNodeModel) { + this.__innerNodes[innerNodeId] = innerNodeModel; + }, + + isInnerNode: function(inputNodeId) { + return (inputNodeId in this.__innerNodes); + }, + + getExposedInnerNodes: function(recursive = false) { + const innerNodes = this.getInnerNodes(recursive); + let exposedInnerNodes = {}; + for (const innerNodeId in innerNodes) { + const innerNode = innerNodes[innerNodeId]; + if (innerNode.getIsOutputNode()) { + exposedInnerNodes[innerNodeId] = innerNode; + } + } + return exposedInnerNodes; + }, + + getInputNodes: function() { + return this.__inputNodes; + }, + + populateNodeData: function(nodeData) { + if (nodeData) { + this.setInputData(nodeData); + this.setOutputData(nodeData); + + if (nodeData.position) { + this.setPosition(nodeData.position.x, nodeData.position.y); + } + + if (nodeData.inputNodes) { + this.__inputNodes = nodeData.inputNodes; + } + + if (nodeData.outputNode) { + this.setIsOutputNode(nodeData.outputNode); + } + + if (nodeData.label) { + this.setLabel(nodeData.label); + } + } + }, + + __addSettings: function(inputs) { + if (inputs === null) { + return; + } + let form = this.__settingsForm = new qxapp.component.form.Auto(inputs); + form.addListener("linkAdded", e => { + let changedField = e.getData(); + this.getPropsWidget().linkAdded(changedField); + }, this); + form.addListener("linkRemoved", e => { + let changedField = e.getData(); + this.getPropsWidget().linkRemoved(changedField); + }, this); + + let propsWidget = new qxapp.component.form.renderer.PropForm(form); + this.setPropsWidget(propsWidget); + propsWidget.addListener("RemoveLink", e => { + let changedField = e.getData(); + this.__settingsForm.removeLink(changedField); + }, this); + }, + + __addOutputs: function(outputs) { + this.__outputs = outputs; + }, + + setInputData: function(nodeData) { + if (this.__settingsForm && nodeData) { + this.__settingsForm.setData(nodeData.inputs); + } + }, + + setOutputData: function(nodeData) { + if ("outputs" in nodeData) { + for (const outputKey in nodeData.outputs) { + this.__outputs[outputKey].value = nodeData.outputs[outputKey]; + } + } + }, + + addPortLink: function(fromNodeId, fromPortId, toPortId) { + this.__settingsForm.addLink(fromNodeId, fromPortId, toPortId); + }, + + addInputNode: function(inputNodeId) { + if (!this.__inputNodes.includes(inputNodeId)) { + this.__inputNodes.push(inputNodeId); + } + }, + + removeInputNode: function(inputNodeId) { + const index = this.__inputNodes.indexOf(inputNodeId); + if (index > -1) { + this.__inputNodes.splice(index, 1); + return true; + } + return false; + }, + + isInputNode: function(inputNodeId) { + const index = this.__inputNodes.indexOf(inputNodeId); + return (index > -1); + }, + + __startInteractiveNode: function() { + let metaData = this.__metaData; + if (metaData.type == "dynamic") { + const slotName = "startDynamic"; + let socket = qxapp.wrappers.WebSocket.getInstance(); + socket.on(slotName, function(val) { + const { + data, + error + } = val; + if (error) { + console.error("Error starting dynamic service: ", data); + return; + } + const publishedPort = data["published_port"]; + const entryPointD = data["entry_point"]; + const nodeId = data["service_uuid"]; + if (nodeId !== this.getNodeId()) { + return; + } + if (publishedPort) { + const entryPoint = entryPointD ? ("/" + entryPointD) : ""; + const srvUrl = "http://" + window.location.hostname + ":" + publishedPort + entryPoint; + this.setServiceUrl(srvUrl); + let button = new qx.ui.form.Button().set({ + icon: "@FontAwesome5Solid/play-circle/32" + }); + this.set({ + viewerButton: button + }); + button.addListener("execute", e => { + this.fireDataEvent("ShowViewer", { + url: srvUrl, + name: this.getLabel(), + nodeId: this.getNodeId() + }); + }, this); + const msg = "Service ready on " + srvUrl; + const msgData = { + nodeLabel: this.getLabel(), + msg: msg + }; + this.fireDataEvent("ShowInLogger", msgData); + console.log(this.getLabel(), msg); + } + }, this); + let data = { + serviceKey: metaData.key, + serviceVersion: metaData.version, + nodeId: this.getNodeId() + }; + socket.emit(slotName, data); + } + }, + + setPosition: function(x, y) { + this.__posX = x; + this.__posY = y; + }, + + getPosition: function() { + return { + x: this.__posX, + y: this.__posY + }; + } + } +}); diff --git a/services/web/client/source/class/qxapp/data/model/Project.js b/services/web/client/source/class/qxapp/data/model/Project.js deleted file mode 100644 index 89c8b80d4b2..00000000000 --- a/services/web/client/source/class/qxapp/data/model/Project.js +++ /dev/null @@ -1,94 +0,0 @@ -qx.Class.define("qxapp.data.model.Project", - { - extend: qx.core.Object, - - construct: function(prjData) { - this.base(arguments); - - this.set({ - id: prjData.id, - name: prjData.name, - description: prjData.description, - thumbnail: prjData.thumbnail, - collaborators: prjData.collaborators, - creationDate: prjData.creationDate, - lastChangeDate: prjData.lastChangeDate, - workbench: prjData.workbench - }); - }, - - properties: { - id: { - check: "String", - event: "changeId", - nullable: true - }, - - name: { - check: "String", - init: "Unnamed" - }, - - description: { - check: "String", - nullable: true - }, - - notes: { - check: "String", - nullable: true - }, - - thumbnail: { - check: "String", - nullable: true - }, - - collaborators: { - check: "Object", - nullable: true - }, - - creationDate: { - check: "Date", - nullable: true - }, - - lastChangeDate: { - check: "Date", - nullable: true - }, - - workbench: { - check: "Object", - nullable: true - } - }, - - members: { - - toString: function() { - // return qx.dev.Debug.debugProperties(this, 3, false, 2); - let newLine = "\n"; - let indent = 4; - let html = false; - const maxLevel = 5; - let message = ""; - - let properties = this.constructor.$$properties; - for (let key in properties) { - message += newLine; - // print out the indentation - for (var j = 0; j < indent; j++) { - message += "-"; - } - message += " " + key + ": " + this.toString( - this["get" + qx.lang.String.firstUp(key)](), maxLevel - 1, html, indent + 1 - ); - } - return message; - } - - } - - }); diff --git a/services/web/client/source/class/qxapp/data/model/ProjectModel.js b/services/web/client/source/class/qxapp/data/model/ProjectModel.js new file mode 100644 index 00000000000..769869e67ea --- /dev/null +++ b/services/web/client/source/class/qxapp/data/model/ProjectModel.js @@ -0,0 +1,98 @@ +qx.Class.define("qxapp.data.model.ProjectModel", { + extend: qx.core.Object, + + construct: function(prjData) { + this.base(arguments); + + if (prjData) { + this.set({ + uuid: prjData.projectUuid || this.getUuid(), + name: prjData.name || this.getName(), + description: prjData.description || this.getDescription(), + notes: prjData.notes || this.getNotes(), + thumbnail: prjData.thumbnail || this.getThumbnail(), + collaborators: prjData.collaborators || this.getCollaborators(), + creationDate: new Date(prjData.creationDate) || this.getCreationDate(), + lastChangeDate: new Date(prjData.lastChangeDate) || this.getLastChangeDate() + }); + } + + if (prjData && prjData.workbench) { + this.setWorkbenchModel(new qxapp.data.model.WorkbenchModel(this.getName(), prjData.workbench)); + } else { + this.setWorkbenchModel(new qxapp.data.model.WorkbenchModel(this.getName(), {})); + } + }, + + properties: { + uuid: { + check: "String", + nullable: false, + init: qxapp.utils.Utils.uuidv4() + }, + + name: { + check: "String", + nullable: false, + init: "New Project" + }, + + description: { + check: "String", + nullable: true, + init: "Empty" + }, + + notes: { + check: "String", + nullable: true, + init: "Empty" + }, + + thumbnail: { + check: "String", + nullable: true, + init: "https://imgplaceholder.com/171x96/cccccc/757575/ion-plus-round" + }, + + collaborators: { + check: "Object", + nullable: true, + init: {} + }, + + creationDate: { + check: "Date", + nullable: true, + init: new Date() + }, + + lastChangeDate: { + check: "Date", + nullable: true, + init: new Date() + }, + + workbenchModel: { + check: "qxapp.data.model.WorkbenchModel", + nullable: false + } + }, + + members: { + serializeProject: function() { + this.setLastChangeDate(new Date()); + + let jsonObject = {}; + let properties = this.constructor.$$properties; + for (let key in properties) { + if (key === "workbenchModel") { + jsonObject["workbench"] = this.getWorkbenchModel().serializeWorkbench(); + } else { + jsonObject[key] = this.get(key); + } + } + return jsonObject; + } + } +}); diff --git a/services/web/client/source/class/qxapp/data/model/WorkbenchModel.js b/services/web/client/source/class/qxapp/data/model/WorkbenchModel.js new file mode 100644 index 00000000000..2d5a73e79eb --- /dev/null +++ b/services/web/client/source/class/qxapp/data/model/WorkbenchModel.js @@ -0,0 +1,233 @@ +/* eslint no-warning-comments: "off" */ + +qx.Class.define("qxapp.data.model.WorkbenchModel", { + extend: qx.core.Object, + + construct: function(prjName, wbData) { + this.base(arguments); + + this.__nodesTopLevel = {}; + + this.setProjectName(prjName); + this.createNodeModels(wbData); + this.createLinks(wbData); + }, + + properties: { + projectName: { + check: "String", + nullable: false + } + }, + + events: { + "WorkbenchModelChanged": "qx.event.type.Event", + "ShowInLogger": "qx.event.type.Event" + }, + + members: { + __nodesTopLevel: null, + + isContainer: function() { + return false; + }, + + getNodeModel: function(nodeId) { + const allNodes = this.getNodeModels(true); + const exists = Object.prototype.hasOwnProperty.call(allNodes, nodeId); + if (exists) { + return allNodes[nodeId]; + } + return null; + }, + + getNodeModels: function(recursive = false) { + let nodes = Object.assign({}, this.__nodesTopLevel); + if (recursive) { + for (const nodeId in this.__nodesTopLevel) { + let innerNodes = this.__nodesTopLevel[nodeId].getInnerNodes(true); + nodes = Object.assign(nodes, innerNodes); + } + } + return nodes; + }, + + getPath: function(nodeId) { + let pathWithIds = this.getPathWithId(nodeId); + let nodePath = []; + for (let i=0; i { + this.fireDataEvent("ShowInLogger", e.getData()); + }, this); + return nodeModel; + }, + + createNodeModels: function(workbenchData) { + let keys = Object.keys(workbenchData); + for (let i=0; i 1) { + if (keys[nKeys-1] === keys[nKeys-2]) { + console.log(nodeId, "will never be created, parent missing", nodeData.parent); + return; + } + } + continue; + } + } + let nodeModel = null; + if ("key" in nodeData) { + // not container + nodeModel = this.createNodeModel(nodeData.key, nodeData.version, nodeId, nodeData); + } else { + // container + nodeModel = this.createNodeModel(null, null, nodeId, nodeData); + } + if ("parent" in nodeData) { + let parentModel = this.getNodeModel(nodeData.parent); + this.addNodeModel(nodeModel, parentModel); + } else { + this.addNodeModel(nodeModel); + } + } + }, + + addNodeModel: function(nodeModel, parentNodeModel) { + const uuid = nodeModel.getNodeId(); + if (parentNodeModel) { + parentNodeModel.addInnerNode(uuid, nodeModel); + nodeModel.setParentNodeId(parentNodeModel.getNodeId()); + } else { + this.__nodesTopLevel[uuid] = nodeModel; + } + this.fireEvent("WorkbenchModelChanged"); + }, + + removeNode: function(nodeModel) { + // TODO: only works with top level nodes + const nodeId = nodeModel.getNodeId(); + const exists = Object.prototype.hasOwnProperty.call(this.__nodesTopLevel, nodeId); + if (exists) { + if (nodeModel.getMetaData().type == "dynamic") { + const slotName = "stopDynamic"; + let socket = qxapp.wrappers.WebSocket.getInstance(); + let data = { + nodeId: nodeModel.getNodeId() + }; + socket.emit(slotName, data); + } + delete this.__nodesTopLevel[nodeModel.getNodeId()]; + this.fireEvent("WorkbenchModelChanged"); + } + return exists; + }, + + createLink: function(outputNodeId, inputNodeId) { + let node = this.getNodeModel(inputNodeId); + if (node) { + node.addInputNode(outputNodeId); + } + }, + + createLinks: function(workbenchData) { + for (const nodeId in workbenchData) { + const nodeData = workbenchData[nodeId]; + if (nodeData.inputNodes) { + for (let i=0; i < nodeData.inputNodes.length; i++) { + const outputNodeId = nodeData.inputNodes[i]; + this.createLink(outputNodeId, nodeId); + } + } + } + }, + + removeLink: function(outputNodeId, inputNodeId) { + let node = this.getNodeModel(inputNodeId); + if (node) { + return node.removeInputNode(outputNodeId); + } + return false; + }, + + serializeWorkbench: function(saveContainers = true, savePosition = true) { + let workbench = {}; + const allModels = this.getNodeModels(true); + for (const nodeId in allModels) { + const nodeModel = allModels[nodeId]; + if (!saveContainers && nodeModel.isContainer()) { + continue; + } + + // node generic + let node = workbench[nodeModel.getNodeId()] = { + label: nodeModel.getLabel(), + inputs: nodeModel.getInputValues(), // can a container have inputs? + inputNodes: nodeModel.getInputNodes(), + outputNode: nodeModel.getIsOutputNode(), + outputs: nodeModel.getOutputValues(), // can a container have outputs? + parent: nodeModel.getParentNodeId() + }; + + if (savePosition) { + node.position = { + x: nodeModel.getPosition().x, + y: nodeModel.getPosition().y + }; + } + + // node especific + if (!nodeModel.isContainer()) { + node.key = nodeModel.getMetaData().key; + node.version = nodeModel.getMetaData().version; + } + } + return workbench; + } + } +}); diff --git a/services/web/client/source/class/qxapp/desktop/LayoutManager.js b/services/web/client/source/class/qxapp/desktop/LayoutManager.js index d59c557b093..a5176b25b26 100644 --- a/services/web/client/source/class/qxapp/desktop/LayoutManager.js +++ b/services/web/client/source/class/qxapp/desktop/LayoutManager.js @@ -13,29 +13,46 @@ qx.Class.define("qxapp.desktop.LayoutManager", { this.__navBar = this.__createNavigationBar(); this.__navBar.setHeight(100); + this.__navBar.addListener("NodeDoubleClicked", e => { + if (this.__prjEditor) { + let nodeId = e.getData(); + this.__prjEditor.nodeSelected(nodeId); + } + }, this); this.add(this.__navBar); - this.__prjStack = this.__getPrjStack(); + let prjStack = this.__prjStack = new qx.ui.container.Stack(); + + this.__prjBrowser = new qxapp.desktop.PrjBrowser(); + prjStack.add(this.__prjBrowser); this.add(this.__prjStack, { flex: 1 }); - this.__navBar.addListener("HomePressed", function() { + this.__navBar.addListener("DashboardPressed", function() { this.__prjStack.setSelection([this.__prjBrowser]); - this.__navBar.setCurrentStatus("Browser"); + this.__navBar.setMainViewCaption("Dashboard"); }, this); - this.__prjBrowser.addListener("StartProject", function(e) { - let project = e.getData(); + this.__prjBrowser.addListener("StartProject", e => { + const data = e.getData(); + const projectUuid = data.projectUuid; + const projectName = data.name; if (this.__prjEditor) { this.__prjStack.remove(this.__prjEditor); } - this.__prjEditor = new qxapp.desktop.PrjEditor(project.getProjectId()); + this.__prjEditor = new qxapp.desktop.PrjEditor(projectUuid); this.__prjStack.add(this.__prjEditor); this.__prjStack.setSelection([this.__prjEditor]); - this.__navBar.setCurrentStatus(project.getName()); - // this.__PrjEditor.showSettings(false); + this.__navBar.setMainViewCaption([{ + "root": projectName + }]); + + this.__prjEditor.addListener("ChangeMainViewCaption", function(ev) { + const elements = ev.getData(); + this.__navBar.setMainViewCaption(elements); + }, this); }, this); }, @@ -49,19 +66,10 @@ qx.Class.define("qxapp.desktop.LayoutManager", { __createNavigationBar: function() { let navBar = new qxapp.desktop.NavigationBar(); - navBar.setCurrentStatus("Browser"); + navBar.setMainViewCaption("Dashboard"); return navBar; }, - __getPrjStack: function() { - let prjStack = new qx.ui.container.Stack(); - - this.__prjBrowser = new qxapp.desktop.PrjBrowser(); - prjStack.add(this.__prjBrowser); - - return prjStack; - }, - __nodeCheck: function() { /** a little ajv test */ let nodeCheck = new qx.io.request.Xhr("/resource/qxapp/node-meta-v0.0.1.json"); @@ -70,23 +78,15 @@ qx.Class.define("qxapp.desktop.LayoutManager", { try { let ajv = new qxapp.wrappers.Ajv(data); let store = qxapp.data.Store.getInstance(); - [ - "builtInServicesRegistered", - "servicesRegistered", - "interactiveServicesRegistered" - ].forEach(event => { - store.addListener(event, ev => { - const services = ev.getData(); - for (let i = 0; i < services.length; i++) { - const service = services[i]; - let check = ajv.validate(service); - console.log("services validation result " + service.key + ":", check); - } - }, this); + store.addListener("servicesRegistered", ev => { + const services = ev.getData(); + for (let i = 0; i < services.length; i++) { + const service = services[i]; + let check = ajv.validate(service); + console.log("services validation result " + service.key + ":", check); + } }); - store.getBuiltInServicesAsync(); - store.getComputationalServices(); - store.getInteractiveServices(); + store.getServices(); } catch (err) { console.error(err); } diff --git a/services/web/client/source/class/qxapp/desktop/NavigationBar.js b/services/web/client/source/class/qxapp/desktop/NavigationBar.js index 29bfabde0f6..6d87799362d 100644 --- a/services/web/client/source/class/qxapp/desktop/NavigationBar.js +++ b/services/web/client/source/class/qxapp/desktop/NavigationBar.js @@ -1,5 +1,7 @@ /* eslint no-warning-comments: "off" */ +const NAVIGATION_BUTTON_HEIGHT = 32; + qx.Class.define("qxapp.desktop.NavigationBar", { extend: qx.ui.container.Composite, @@ -19,23 +21,58 @@ qx.Class.define("qxapp.desktop.NavigationBar", { const commonBtnSettings = { allowGrowY: false, minWidth: 32, - minHeight: 32 + minHeight: NAVIGATION_BUTTON_HEIGHT }; - let homeBtn = new qx.ui.form.Button(); - homeBtn.set(commonBtnSettings); - homeBtn.setIcon("@FontAwesome5Solid/home/32"); - this.add(homeBtn); - this._currentState = new qx.ui.basic.Label().set({ - minWidth: 20 + let logo = new qx.ui.basic.Image("qxapp/osparc-white-small.png").set({ + maxHeight: NAVIGATION_BUTTON_HEIGHT, + maxWidth: 92, + scale: true }); - this.add(this._currentState); + this.add(logo); + + this.add(new qx.ui.toolbar.Separator()); + + let hBox = new qx.ui.layout.HBox(5).set({ + alignY: "middle" + }); + let mainViewCaptionLayout = this.__mainViewCaptionLayout = new qx.ui.container.Composite(hBox); + this.add(mainViewCaptionLayout); + this.add(new qx.ui.core.Spacer(5), { flex: 1 }); + + let dashboardBtn = new qx.ui.form.Button(this.tr("Dashboard")); + dashboardBtn.set(commonBtnSettings); + dashboardBtn.addListener("execute", function() { + this.fireEvent("DashboardPressed"); + }, this); + this.add(dashboardBtn); + + this.add(new qx.ui.toolbar.Separator()); + + let pubPrjsBtn = new qx.ui.form.Button(this.tr("Public Projects")); + pubPrjsBtn.set(commonBtnSettings); + this.add(pubPrjsBtn); + + this.add(new qx.ui.toolbar.Separator()); + + let forumBtn = new qx.ui.form.Button(this.tr("Forum")); + forumBtn.set(commonBtnSettings); + this.add(forumBtn); + + this.add(new qx.ui.toolbar.Separator()); + + let helpBtn = new qx.ui.form.Button(this.tr("Help")); + helpBtn.set(commonBtnSettings); + this.add(helpBtn); + + this.add(new qx.ui.toolbar.Separator()); + const dummyUser="bizzy"; let userLbl = new qx.ui.basic.Label("@" + dummyUser).set({ minWidth: 20 @@ -44,24 +81,56 @@ qx.Class.define("qxapp.desktop.NavigationBar", { let userBtn = this.__createUserBtn(); userBtn.set(commonBtnSettings); - userBtn.setIcon(qxapp.utils.Avatar.getUrl(dummyUser + "@itis.ethz.ch", 32)); + userBtn.setIcon(qxapp.utils.Avatar.getUrl(dummyUser + "@itis.ethz.ch", NAVIGATION_BUTTON_HEIGHT)); this.add(userBtn); - - - // Connect listeners - homeBtn.addListener("execute", function() { - this.fireEvent("HomePressed"); - }, this); }, events: { - "HomePressed": "qx.event.type.Event" + "NodeDoubleClicked": "qx.event.type.Data", + "DashboardPressed": "qx.event.type.Event" }, members: { + __mainViewCaptionLayout: null, + + setMainViewCaption: function(newLabel) { + this.__mainViewCaptionLayout.removeAll(); + if (typeof newLabel === "string") { + this.__showMainViewCaptionAsText(newLabel); + } else if (Array.isArray(newLabel)) { + this.__showMainViewCaptionAsButtons(newLabel); + } + }, + + __showMainViewCaptionAsText: function(newLabel) { + const navBarLabelFont = qx.bom.Font.fromConfig(qxapp.theme.Font.fonts["nav-bar-label"]); + let mainViewCaption = this.__mainViewCaption = new qx.ui.basic.Label(newLabel).set({ + font: navBarLabelFont + }); + this.__mainViewCaptionLayout.add(mainViewCaption); + }, - setCurrentStatus: function(newLabel) { - this._currentState.setValue("Showing: " + newLabel); + __showMainViewCaptionAsButtons: function(newLabels) { + const navBarLabelFont = qx.bom.Font.fromConfig(qxapp.theme.Font.fonts["nav-bar-label"]); + for (let i=0; i").set({ + font: navBarLabelFont + }); + this.__mainViewCaptionLayout.add(mainViewCaption); + } + } }, __createUserBtn: function() { @@ -82,7 +151,7 @@ qx.Class.define("qxapp.desktop.NavigationBar", { preferences.addListener("execute", this.__onOpenAccountSettings, this); let logout = new qx.ui.menu.Button("Logout"); - logout.addListener("execute", function(e) { + logout.addListener("execute", e => { let app = qx.core.Init.getApplication(); app.logout(); }); @@ -108,10 +177,8 @@ qx.Class.define("qxapp.desktop.NavigationBar", { let win = this.__preferencesWin; if (win) { + win.center(); win.open(); - - const [left, top] = qxapp.utils.Dom.getCenteredLoc(win.getWidth(), win.getHeight()); - win.moveTo(left, top); } } } diff --git a/services/web/client/source/class/qxapp/desktop/PrjBrowser.js b/services/web/client/source/class/qxapp/desktop/PrjBrowser.js index 63a4ece2834..512bec34e20 100644 --- a/services/web/client/source/class/qxapp/desktop/PrjBrowser.js +++ b/services/web/client/source/class/qxapp/desktop/PrjBrowser.js @@ -40,9 +40,13 @@ qx.Class.define("qxapp.desktop.PrjBrowser", { // prjCtr.setModel(); // Monitors change in selection - prjCtr.getSelection().addListener("change", function(e) { + prjCtr.getSelection().addListener("change", e => { const selectedItem = e.getTarget().toArray()[0]; - this.fireDataEvent("StartProject", selectedItem); + const data = { + name: selectedItem.getName(), + projectUuid: selectedItem.getProjectUuid() + }; + this.fireDataEvent("StartProject", data); }, this); }, @@ -65,9 +69,13 @@ qx.Class.define("qxapp.desktop.PrjBrowser", { // prjCtr.setModel(); // Monitors change in selection - prjCtr.getSelection().addListener("change", function(e) { + prjCtr.getSelection().addListener("change", e => { const selectedItem = e.getTarget().toArray()[0]; - this.fireDataEvent("StartProject", selectedItem); + const data = { + name: selectedItem.getName(), + projectUuid: selectedItem.getProjectUuid() + }; + this.fireDataEvent("StartProject", data); }, this); }, @@ -113,8 +121,8 @@ qx.Class.define("qxapp.desktop.PrjBrowser", { .map( (p, i) => qx.data.marshal.Json.createModel({ name: p.name, - thumbnail: "https://placeimg.com/171/96/tech/grayscale/?"+i+".jpg", - projectId: i, + thumbnail: p.thumbnail, + projectUuid: p.projectUuid, created: p.creationDate }) ) @@ -126,7 +134,7 @@ qx.Class.define("qxapp.desktop.PrjBrowser", { data.insertAt(0, qx.data.marshal.Json.createModel({ name: this.tr("New Project"), thumbnail: "@MaterialIcons/create/40", - projectId: null, + projectUuid: null, created: null })); return data; diff --git a/services/web/client/source/class/qxapp/desktop/PrjEditor.js b/services/web/client/source/class/qxapp/desktop/PrjEditor.js index 1bf936ab0bc..38f1450c8c4 100644 --- a/services/web/client/source/class/qxapp/desktop/PrjEditor.js +++ b/services/web/client/source/class/qxapp/desktop/PrjEditor.js @@ -2,151 +2,333 @@ qx.Class.define("qxapp.desktop.PrjEditor", { extend: qx.ui.splitpane.Pane, - construct: function(projectId) { + construct: function(projectUuid) { this.base(arguments, "horizontal"); - let splitter = this.__splitter = this.getChildControl("splitter"); + let project = this.__projectDocument = this.__getProjectDocument(projectUuid); + this.setProjectId(project.getUuid()); - const settingsWidth = this.__settingsWidth = 500; - let settingsView = this.__settingsView = new qxapp.components.workbench.SettingsView().set({ - width: Math.round(0.75 * settingsWidth) + let mainPanel = this.__mainPanel = new qxapp.desktop.mainPanel.MainPanel().set({ + minWidth: 1000 }); - - let settingsBox = this.__settingsBox = new qx.ui.container.Composite(new qx.ui.layout.Canvas()).set({ + let sidePanel = this.__sidePanel = new qxapp.desktop.sidePanel.SidePanel().set({ minWidth: 0, - visibility: "excluded", - maxWidth: settingsWidth, - width: Math.round(0.75 * settingsWidth) + maxWidth: 800, + width: 600 }); - settingsBox.add(settingsView, { - top: 0, - right: 0 - }); + this.add(mainPanel, 1); // flex 1 + this.add(sidePanel, 0); // flex 0 - this.add(settingsBox, 0); + this.initDefault(); + this.connectEvents(); + }, - settingsBox.addListener("changeWidth", e => { - let width = e.getData(); - if (width != 0) { - settingsView.setWidth(width); - } - }); + properties: { + projectId: { + check: "String", + nullable: false + }, + + canStart: { + nullable: false, + init: true, + check: "Boolean", + apply : "__applyCanStart" + } + }, + + events: { + "ChangeMainViewCaption": "qx.event.type.Data" + }, + + members: { + __pipelineId: null, + __mainPanel: null, + __sidePanel: null, + __workbenchView: null, + __treeView: null, + __extraView: null, + __loggerView: null, + __settingsView: null, + __transDeco: null, + __splitter: null, + __projectDocument: null, + __currentNodeId: null, + + initDefault: function() { + let project = this.__projectDocument; + + let treeView = this.__treeView = new qxapp.component.widget.TreeTool(project.getName(), project.getWorkbenchModel()); + this.__sidePanel.setTopView(treeView); + + let extraView = this.__extraView = new qx.ui.container.Composite(new qx.ui.layout.Canvas()).set({ + minHeight: 200, + maxHeight: 500 + }); + this.__sidePanel.setMidView(extraView); - let workbenchData = this.__getProjectDocument(projectId); - let workbench = this.__workbench = new qxapp.components.workbench.Workbench(workbenchData); - this.add(workbench, 1); - - workbench.addListenerOnce("appear", () => { - workbench.getContentElement().getDomElement() - .addEventListener("transitionend", () => { - [ - settingsView, - splitter, - settingsBox, - workbench - ].forEach(w => { - w.resetDecorator(); + let loggerView = this.__loggerView = new qxapp.component.widget.logger.LoggerView(); + this.__sidePanel.setBottomView(loggerView); + + let workbenchView = this.__workbenchView = new qxapp.component.workbench.WorkbenchView(project.getWorkbenchModel()); + this.showInMainView(workbenchView, "root"); + + let settingsView = this.__settingsView = new qxapp.component.widget.SettingsView().set({ + minHeight: 200, + maxHeight: 500 + }); + settingsView.setWorkbenchModel(project.getWorkbenchModel()); + }, + + connectEvents: function() { + this.__mainPanel.getControls().addListener("SavePressed", function() { + this.serializeProjectDocument(); + }, this); + + this.__mainPanel.getControls().addListener("StartPipeline", function() { + if (this.getCanStart()) { + this.__startPipeline(); + } else { + this.__workbenchView.getLogger().info("Can not start pipeline"); + } + }, this); + + this.__mainPanel.getControls().addListener("StopPipeline", function() { + this.__stopPipeline(); + }, this); + + this.__projectDocument.getWorkbenchModel().addListener("WorkbenchModelChanged", function() { + this.__workbenchModelChanged(); + }, this); + + this.__projectDocument.getWorkbenchModel().addListener("ShowInLogger", e => { + const data = e.getData(); + const nodeLabel = data.nodeLabel; + const msg = data.msg; + this.getLogger().info(nodeLabel, msg); + }, this); + + [ + this.__treeView, + this.__workbenchView + ].forEach(wb => { + wb.addListener("NodeDoubleClicked", e => { + let nodeId = e.getData(); + this.nodeSelected(nodeId); + }, this); + }); + + this.__settingsView.addListener("ShowViewer", e => { + const data = e.getData(); + const url = data.url; + const name = data.name; + // const nodeId = data.nodeId; + + let iframe = this.__createIFrame(url, name); + // this.showInMainView(iframe, nodeId); + this.__mainPanel.setMainView(iframe); + + // Workaround for updating inputs + if (name === "3d-viewer") { + let urlUpdate = url + "/retrieve"; + let req = new qx.io.request.Xhr(); + req.set({ + url: urlUpdate, + method: "POST" }); - if (settingsBox.getWidth() === 0) { - settingsBox.exclude(); - } - }); - }); + req.send(); + } + }, this); + }, + nodeSelected: function(nodeId) { + if (!nodeId) { + return; + } + this.__currentNodeId = nodeId; + this.__treeView.nodeSelected(nodeId); - this.showSettings(false); + if (nodeId === "root") { + const workbenchModel = this.__projectDocument.getWorkbenchModel(); + this.__workbenchView.loadModel(workbenchModel); + this.showInMainView(this.__workbenchView, nodeId); + } else { + let nodeModel = this.__projectDocument.getWorkbenchModel().getNodeModel(nodeId); - this.__settingsView.addListener("SettingsEdited", function() { - this.showSettings(false); - }, this); + let widget; + if (nodeModel.isContainer()) { + widget = this.__workbenchView; + } else { + this.__settingsView.setNodeModel(nodeModel); + if (nodeModel.getMetaData().type === "dynamic") { + const widgetManager = qxapp.component.widget.WidgetManager.getInstance(); + widget = widgetManager.getWidgetForNode(nodeModel); + if (!widget) { + widget = this.__settingsView; + } + } else { + widget = this.__settingsView; + } + } + this.showInMainView(widget, nodeId); - this.__settingsView.addListener("ShowViewer", function(e) { - let data = e.getData(); - let viewerWin = this.__createBrowserWindow(data.url, data.name); + if (nodeModel.isContainer()) { + this.__workbenchView.loadModel(nodeModel); + } + } + }, + + __workbenchModelChanged: function() { + this.__treeView.buildTree(); + this.__treeView.nodeSelected(this.__currentNodeId); + }, + + showInMainView: function(widget, nodeId) { + this.__mainPanel.setMainView(widget); + let nodePath = this.__projectDocument.getWorkbenchModel().getPathWithId(nodeId); + this.fireDataEvent("ChangeMainViewCaption", nodePath); + }, - // const metadata = e.getData().metadata; - // const nodeId = e.getData().nodeId; - // let url = "http://" + window.location.hostname + ":" + metadata.viewer.port; - // let viewerWin = this.__createBrowserWindow(url, metadata.name); + showInExtraView: function(widget) { + this.__sidePanel.setMidView(widget); + }, - this.__workbench.addWindowToDesktop(viewerWin); + getLogger: function() { + return this.__loggerView; + }, - // Workaround for updating inputs - if (data.name === "3d-viewer") { - let urlUpdate = data.url + "/retrieve"; - let req = new qx.io.request.Xhr(); - req.set({ - url: urlUpdate, - method: "POST" - }); - req.send(); + __getProjectDocument: function(projectId) { + let project = null; + if (projectId) { + let projectData = qxapp.data.Store.getInstance().getProjectData(projectId); + projectData.id = String(projectId); + project = new qxapp.data.model.ProjectModel(projectData); + } else { + project = new qxapp.data.model.ProjectModel(); } - }, this); - - // this.__settingsView.addListener("NodeProgress", function(e) { - // const nodeId = e.getData()[0]; - // const progress = e.getData()[1]; - // this.__workbench.updateProgress(nodeId, progress); - // }, this); - - this.__workbench.addListener("NodeDoubleClicked", function(e) { - let node = e.getData(); - this.__settingsView.setNode(node); - this.showSettings(true); - }, this); - - this.__transDeco = new qx.ui.decoration.Decorator().set({ - transitionProperty: ["left", "right", "width"], - transitionDuration: "0.3s", - transitionTimingFunction: "ease" - }); - }, + return project; + }, - members: { - __pane: null, - __settingsView: null, - __settingsBox: null, - __workbench: null, - __settingsWidth: null, - __transDeco: null, - __splitter: null, - __projectId: null, + __startPipeline: function() { + // ui start pipeline + // this.clearProgressData(); + + let socket = qxapp.wrappers.WebSocket.getInstance(); - showSettings: function(showSettings) { - if (showSettings) { - this.__settingsBox.show(); + // callback for incoming logs + const slotName = "logger"; + if (!socket.slotExists(slotName)) { + socket.on(slotName, function(data) { + let d = JSON.parse(data); + let node = d["Node"]; + let msg = d["Message"]; + this.__updateLogger(node, msg); + }, this); } - qx.ui.core.queue.Manager.flush(); - this.__settingsBox.set({ - decorator: this.__transDeco, - width: showSettings ? Math.round(this.__settingsWidth * 0.75) : 0 - }); - this.__settingsView.set({ - decorator: this.__transDeco - }); - this.__workbench.set({ - decorator: this.__transDeco + socket.emit(slotName); + + // callback for incoming progress + if (!socket.slotExists("progress")) { + socket.on("progress", function(data) { + let d = JSON.parse(data); + let node = d["Node"]; + let progress = 100*Number.parseFloat(d["Progress"]).toFixed(4); + this.__workbenchView.updateProgress(node, progress); + }, this); + } + + // post pipeline + this.__pipelineId = null; + const saveContainers = false; + const savePosition = false; + let currentPipeline = this.__projectDocument.getWorkbenchModel().serializeWorkbench(saveContainers, savePosition); + console.log(currentPipeline); + let req = new qx.io.request.Xhr(); + let data = {}; + data = currentPipeline; + data["pipeline_mockup_id"] = qxapp.utils.Utils.uuidv4(); + req.set({ + url: "/start_pipeline", + method: "POST", + requestData: qx.util.Serializer.toJson(data) }); - this.__splitter.set({ - decorator: this.__transDeco + req.addListener("success", this.__onPipelinesubmitted, this); + req.addListener("error", e => { + this.setCanStart(true); + this.getLogger().error("Workbench", "Error submitting pipeline"); + }, this); + req.addListener("fail", e => { + this.setCanStart(true); + this.getLogger().error("Workbench", "Failed submitting pipeline"); + }, this); + req.send(); + + this.getLogger().info("Workbench", "Starting pipeline"); + }, + + __stopPipeline: function() { + let req = new qx.io.request.Xhr(); + let data = {}; + data["pipeline_id"] = this.__pipelineId; + req.set({ + url: "/stop_pipeline", + method: "POST", + requestData: qx.util.Serializer.toJson(data) }); + req.addListener("success", this.__onPipelineStopped, this); + req.addListener("error", e => { + this.setCanStart(false); + this.getLogger().error("Workbench", "Error stopping pipeline"); + }, this); + req.addListener("fail", e => { + this.setCanStart(false); + this.getLogger().error("Workbench", "Failed stopping pipeline"); + }, this); + // req.send(); + + // temporary solution + this.setCanStart(true); + + this.getLogger().info("Workbench", "Stopping pipeline. Not yet implemented"); }, - __getProjectDocument: function(projectId) { - let workbenchData = {}; - if (projectId === null || projectId === undefined) { - projectId = qxapp.utils.Utils.uuidv4(); + __onPipelinesubmitted: function(e) { + let req = e.getTarget(); + + const pipelineId = req.getResponse().pipeline_id; + this.getLogger().debug("Workbench", "Pipeline ID " + pipelineId); + const notGood = [null, undefined, -1]; + if (notGood.includes(pipelineId)) { + this.setCanStart(true); + this.__pipelineId = null; + this.getLogger().error("Workbench", "Submition failed"); } else { - workbenchData = qxapp.data.Store.getInstance().getProjectList()[projectId].workbench; + this.setCanStart(false); + this.__pipelineId = pipelineId; + this.getLogger().info("Workbench", "Pipeline started"); } - this.__projectId = projectId; + }, + + __onPipelineStopped: function(e) { + this.__workbenchView.clearProgressData(); - return workbenchData; + this.setCanStart(true); }, - __createBrowserWindow: function(url, name) { + __applyCanStart: function(value, old) { + this.__mainPanel.getControls().setCanStart(value); + }, + + __updateLogger: function(nodeId, msg) { + let node = this.__workbenchView.getNodeUI(nodeId); + if (node) { + this.getLogger().info(node.getCaption(), msg); + } + }, + + __createIFrame: function(url, name) { console.log("Accessing:", url); let win = new qx.ui.window.Window(name); win.setShowMinimize(false); @@ -164,11 +346,15 @@ qx.Class.define("qxapp.desktop.PrjEditor", { }); win.moveTo(150, 150); - win.addListener("dblclick", function(e) { + win.addListener("dblclick", e => { e.stopPropagation(); }); return win; + }, + + serializeProjectDocument: function() { + console.log("serializeProject", this.__projectDocument.serializeProject()); } } }); diff --git a/services/web/client/source/class/qxapp/desktop/mainPanel/ControlsBar.js b/services/web/client/source/class/qxapp/desktop/mainPanel/ControlsBar.js new file mode 100644 index 00000000000..e64436282fa --- /dev/null +++ b/services/web/client/source/class/qxapp/desktop/mainPanel/ControlsBar.js @@ -0,0 +1,87 @@ +qx.Class.define("qxapp.desktop.mainPanel.ControlsBar", { + extend: qx.ui.core.Widget, + + construct: function() { + this.base(arguments); + + this._setLayout(new qx.ui.layout.HBox(10)); + + let leftBox = new qx.ui.layout.HBox(10, "left"); + this.__leftSide = new qx.ui.container.Composite(leftBox); + this._add(this.__leftSide, { + width: "50%" + }); + + let rightBox = new qx.ui.layout.HBox(10, "right"); + this.__rightSide = new qx.ui.container.Composite(rightBox); + this._add(this.__rightSide, { + width: "50%" + }); + + this.__initDefault(); + + this.setCanStart(true); + }, + + events: { + "SavePressed": "qx.event.type.Event", + "StartPipeline": "qx.event.type.Event", + "StopPipeline": "qx.event.type.Event" + }, + + members: { + __startButton: null, + __stopButton: null, + + __initDefault: function() { + let saveBtn = this.__createSaveButton(); + this.__rightSide.add(saveBtn); + let playBtn = this.__startButton = this.__createStartButton(); + let stopButton = this.__stopButton = this.__createStopButton(); + this.__rightSide.add(playBtn); + this.__rightSide.add(stopButton); + }, + + __createSaveButton: function() { + let saveBtn = this.__saveButton = new qx.ui.form.Button(); + saveBtn.setIcon("@FontAwesome5Solid/save/32"); + saveBtn.addListener("execute", function() { + this.fireEvent("SavePressed"); + }, this); + return saveBtn; + }, + + __createStartButton: function() { + let startButton = new qx.ui.form.Button().set({ + icon: "@FontAwesome5Solid/play/32" + }); + + startButton.addListener("execute", function() { + this.fireEvent("StartPipeline"); + }, this); + + return startButton; + }, + + __createStopButton: function() { + let stopButton = this.__stopButton = new qx.ui.form.Button().set({ + icon: "@FontAwesome5Solid/stop-circle/32" + }); + + stopButton.addListener("execute", function() { + this.fireEvent("StopPipeline"); + }, this); + return stopButton; + }, + + setCanStart: function(value) { + if (value) { + this.__startButton.setVisibility("visible"); + this.__stopButton.setVisibility("excluded"); + } else { + this.__startButton.setVisibility("excluded"); + this.__stopButton.setVisibility("visible"); + } + } + } +}); diff --git a/services/web/client/source/class/qxapp/desktop/mainPanel/MainPanel.js b/services/web/client/source/class/qxapp/desktop/mainPanel/MainPanel.js new file mode 100644 index 00000000000..5a09f1c0c93 --- /dev/null +++ b/services/web/client/source/class/qxapp/desktop/mainPanel/MainPanel.js @@ -0,0 +1,71 @@ +/* eslint no-underscore-dangle: 0 */ + +qx.Class.define("qxapp.desktop.mainPanel.MainPanel", { + extend: qx.ui.core.Widget, + + construct: function() { + this.base(arguments); + + this._setLayout(new qx.ui.layout.VBox(5)); + + // let optionsBar = this.__optionsBar = new qxapp.desktop.mainPanel.OptionsBar(); + let mainView = new qx.ui.core.Widget(); + let controlsBar = this.__controlsBar = new qxapp.desktop.mainPanel.ControlsBar(); + /* + optionsBar.set({ + width: 60, + allowGrowX: false + }); + */ + controlsBar.set({ + height: 60, + allowGrowY: false + }); + + let hBox = this.__hBox = new qx.ui.container.Composite(new qx.ui.layout.HBox(5)); + // hBox.add(optionsBar); + hBox.add(mainView, { + flex: 1 + }); + + this._add(hBox, { + flex: 1 + }); + this._add(controlsBar); + }, + + properties: { + mainView: { + nullable: false, + check : "qx.ui.core.Widget", + apply : "__applyMainView" + } + }, + + events: {}, + + members: { + __hBox: null, + // __optionsBar: null, + __controlsBar: null, + + __applyMainView: function(newWidget) { + // const mainViewIndex = 1; + const mainViewIndex = 0; + if (this.__hBox._indexOf(newWidget) != mainViewIndex) { + this.__hBox._removeAt(mainViewIndex); + this.__hBox._addAt(newWidget, mainViewIndex, { + flex: 1 + }); + } + }, + /* + getOptions: function() { + return this.__optionsBar; + }, + */ + getControls: function() { + return this.__controlsBar; + } + } +}); diff --git a/services/web/client/source/class/qxapp/desktop/mainPanel/OptionsBar.js b/services/web/client/source/class/qxapp/desktop/mainPanel/OptionsBar.js new file mode 100644 index 00000000000..ebd694c6ae5 --- /dev/null +++ b/services/web/client/source/class/qxapp/desktop/mainPanel/OptionsBar.js @@ -0,0 +1,39 @@ +qx.Class.define("qxapp.desktop.mainPanel.OptionsBar", { + extend: qx.ui.core.Widget, + + construct: function() { + this.base(arguments); + + this._setLayout(new qx.ui.layout.VBox(10)); + + this.__initDefault(); + }, + + members: { + __initDefault: function() { + let treeBtn = new qx.ui.form.Button(); + treeBtn.setIcon("@FontAwesome5Solid/bars/32"); + this._add(treeBtn); + + let addBtn = new qx.ui.form.Button(); + addBtn.setIcon("@FontAwesome5Solid/plus/32"); + this._add(addBtn); + + let databaseBtn = new qx.ui.form.Button(); + databaseBtn.setIcon("@FontAwesome5Solid/database/32"); + this._add(databaseBtn); + + let linkBtn = new qx.ui.form.Button(); + linkBtn.setIcon("@FontAwesome5Solid/magnet/32"); + this._add(linkBtn); + + let uploadBtn = new qx.ui.form.Button(); + uploadBtn.setIcon("@FontAwesome5Solid/cloud-upload-alt/32"); + this._add(uploadBtn); + + let shareBtn = new qx.ui.form.Button(); + shareBtn.setIcon("@FontAwesome5Solid/share-alt/32"); + this._add(shareBtn); + } + } +}); diff --git a/services/web/client/source/class/qxapp/desktop/sidePanel/SidePanel.js b/services/web/client/source/class/qxapp/desktop/sidePanel/SidePanel.js new file mode 100644 index 00000000000..cb56bbcb65e --- /dev/null +++ b/services/web/client/source/class/qxapp/desktop/sidePanel/SidePanel.js @@ -0,0 +1,68 @@ +qx.Class.define("qxapp.desktop.sidePanel.SidePanel", { + extend: qx.ui.core.Widget, + + construct: function() { + this.base(arguments); + + this._setLayout(new qx.ui.layout.VBox(10, null, "separator-vertical")); + + let topView = new qx.ui.core.Widget(); + let midView = new qx.ui.core.Widget(); + let bottomView = new qx.ui.core.Widget(); + + this._add(topView, { + flex: 1 + }); + this._add(midView, { + flex: 1 + }); + this._add(bottomView, { + flex: 1 + }); + }, + + properties: { + topView: { + nullable: false, + check : "qx.ui.core.Widget", + apply : "__applyTopView" + }, + + midView: { + nullable: false, + check : "qx.ui.core.Widget", + apply : "__applyMidView" + }, + + bottomView: { + nullable: false, + check : "qx.ui.core.Widget", + apply : "__applyBottomView" + } + }, + + events: {}, + + members: { + __applyTopView: function(newWidget) { + this.__replaceWidgetAt(newWidget, 0); + }, + + __applyMidView: function(newWidget) { + this.__replaceWidgetAt(newWidget, 1); + }, + + __applyBottomView: function(newWidget) { + this.__replaceWidgetAt(newWidget, 2); + }, + + __replaceWidgetAt: function(newWidget, indexOf) { + if (this._indexOf(newWidget) !== indexOf) { + this._removeAt(indexOf); + this._addAt(newWidget, indexOf, { + height: "33%" + }); + } + } + } +}); diff --git a/services/web/client/source/class/qxapp/dev/fake/Data.js b/services/web/client/source/class/qxapp/dev/fake/Data.js index 8847e1ec8e3..5313bb661eb 100644 --- a/services/web/client/source/class/qxapp/dev/fake/Data.js +++ b/services/web/client/source/class/qxapp/dev/fake/Data.js @@ -126,6 +126,7 @@ qx.Class.define("qxapp.dev.fake.Data", { defaultValue: "dog", type: "string", widget: { + /* type: "SelectBox", structure: [ { @@ -137,6 +138,9 @@ qx.Class.define("qxapp.dev.fake.Data", { label: "A Cat" } ] + */ + type: "TextArea", + minHeight: 50 } }, inFile: { @@ -185,6 +189,7 @@ qx.Class.define("qxapp.dev.fake.Data", { getProjectList: function() { return [ { + projectUuid: "07640335-a91f-468c-ab69-a374fa82078d", name: "Sample Project", description: "A little fake project without actual backend", notes: "# title\nThere be dragons inside", @@ -197,6 +202,7 @@ qx.Class.define("qxapp.dev.fake.Data", { }, creationDate: "2018-07-02T16:01:00Z", lastChangeDate: "2018-07-02T16:02:22Z", + thumbnail: "https://placeimg.com/171/96/tech/grayscale/?0.jpg", workbench: { "UUID1": { key: "service/dynamic/itis/file-picker", @@ -222,7 +228,7 @@ qx.Class.define("qxapp.dev.fake.Data", { outNumber: 33 }, position: { - x: 300, + x: 400, y: 10 } }, @@ -237,7 +243,7 @@ qx.Class.define("qxapp.dev.fake.Data", { }, position: { x: 10, - y: 210 + y: 300 } }, "UUID4": { @@ -254,22 +260,26 @@ qx.Class.define("qxapp.dev.fake.Data", { inArea: "some\nmore", inSb: "cat", inFile: { - store: "s3-z43", - path: "bucket33/file.data" + nodeUuid: "UUID1", + output: "outFile" }, inImage: { - store: "s3-z43", - path: "bucket32/file.png" + nodeUuid: "UUID1", + output: "outFile" } }, + inputNodes: [ + "UUID3", + "UUID1" + ], position: { - x: 300, - y: 210 + x: 400, + y: 400 } } } - }, - { + }, { + projectUuid: "9bcf8feb-c1b1-41b6-b201-639cd6ccdba8", name: "Sample Project II", description: "An empty project", notes: "# title\nThere be dragons inside", @@ -282,10 +292,502 @@ qx.Class.define("qxapp.dev.fake.Data", { }, creationDate: "2018-07-08T16:01:00Z", lastChangeDate: "2018-07-09T16:02:22Z", - workbench: {} + thumbnail: "https://placeimg.com/171/96/tech/grayscale/?1.jpg", + workbench: { + "eb51440a-04bd-4847-b457-86c83400abf5": { + key: "service/dynamic/itis/s4l/MaterialDB", + version: "0.0.0", + position: { + x: 50, + y: 50 + } + }, + "bc466582-9240-4d97-9f9e-197b5f3a354b": { + key: "service/dynamic/itis/s4l/Modeler", + version: "0.0.0", + position: { + x: 50, + y: 400 + } + }, + "e5ab3634-875f-4459-ab3f-00c91457ff49": { + key: "service/dynamic/itis/s4l/Simulator/LF/Setup", + version: "0.0.0", + inputs: {}, + position: { + x: 400, + y: 150 + } + }, + "b7cd1659-d366-465b-b712-851b469ba654": { + key: "service/dynamic/itis/s4l/Simulator/LF/Materials", + version: "0.0.0", + inputs: { + modeler: { + nodeUuid: "bc466582-9240-4d97-9f9e-197b5f3a354b", + output: "modeler" + }, + materialDB: { + nodeUuid: "eb51440a-04bd-4847-b457-86c83400abf5", + output: "materialDB" + } + }, + inputNodes: [ + "bc466582-9240-4d97-9f9e-197b5f3a354b", + "eb51440a-04bd-4847-b457-86c83400abf5" + ], + position: { + x: 400, + y: 250 + } + } + } + }, { + projectUuid: "80363288-84c2-49db-95d1-22e1ea78043e", + name: "Macros", + description: "Project containing nested custom macros", + notes: "# title\nBlah", + owner: "UUID-OF-ODEI", + collaborators: { + "UUID-OF-ODEI": [ + "read", + "write" + ] + }, + creationDate: "2018-09-24T16:01:00Z", + lastChangeDate: "2018-09-24T16:02:22Z", + thumbnail: "https://placeimg.com/171/96/tech/grayscale/?15.jpg", + workbench: { + "Sleeper1": { + key: "service/computational/itis/sleeper", + version: "0.0.0", + label: "Sleeper 1", + inputs: { + inNumber: 1 + }, + outputs: { + outNumber: 33 + }, + position: { + x: 50, + y: 50 + } + }, + "Container1": { + label: "Container 1", + inputs: {}, + outputs: {}, + inputNodes: [ + "Sleeper1" + ], + outputNode: false, + position: { + x: 300, + y: 50 + } + }, + "Container2": { + label: "Container 2", + inputs: {}, + outputs: {}, + inputNodes: [], + outputNode: false, + position: { + x: 50, + y: 50 + }, + parent: "Container1" + }, + "Sleeper2": { + key: "service/computational/itis/sleeper", + version: "0.0.0", + inputs: { + inNumber: 3 + }, + inputNodes: [ + "Container2" + ], + position: { + x: 350, + y: 50 + }, + parent: "Container1" + }, + "Sleeper3": { + key: "service/computational/itis/sleeper", + version: "0.0.0", + inputs: { + inNumber: 2 + }, + position: { + x: 50, + y: 50 + }, + parent: "Container2" + } + } + }, { + projectUuid: "345a37ab-5346-4983-951a-19ba2ef9ca0f", + name: "LF Simulator", + description: "LF Simulator", + notes: "", + owner: "UUID-OF-ODEI", + collaborators: {}, + creationDate: "2018-07-08T16:01:00Z", + lastChangeDate: "2018-07-09T16:02:22Z", + thumbnail: "https://placeimg.com/171/96/tech/grayscale/?8.jpg", + workbench: { + "c104bb08-77b1-4157-b9f9-e9df7779df08": { + key: "service/dynamic/itis/s4l/Modeler", + version: "0.0.0", + label: "Modeler 1", + position: { + x: 50, + y: 50 + } + }, + "bf88496d-ddf8-476c-8d6c-24c716c2ae4c": { + key: "service/dynamic/itis/s4l/MaterialDB", + version: "0.0.0", + label: "Material DB 1", + position: { + x: 50, + y: 300 + } + }, + "89e185ca-dda1-4a45-8059-715f2cb17100": { + label: "LF Simulator Container", + position: { + x: 400, + y: 150 + }, + inputs: {}, + outputs: {}, + inputNodes: [ + "bf88496d-ddf8-476c-8d6c-24c716c2ae4c", + "c104bb08-77b1-4157-b9f9-e9df7779df08" + ], + outputNode: false + }, + "SetupId": { + key: "service/dynamic/itis/s4l/Simulator/LF/Setup", + version: "0.0.0", + label: "LF Setup 1", + inputNodes: [], + outputNode: false, + position: { + x: 100, + y: 50 + }, + parent: "89e185ca-dda1-4a45-8059-715f2cb17100" + }, + "MaterialsId": { + key: "service/dynamic/itis/s4l/Simulator/LF/Materials", + version: "0.0.0", + label: "LF Materials 1", + inputNodes: [ + "c104bb08-77b1-4157-b9f9-e9df7779df08", + "bf88496d-ddf8-476c-8d6c-24c716c2ae4c" + ], + outputNode: false, + position: { + x: 100, + y: 150 + }, + parent: "89e185ca-dda1-4a45-8059-715f2cb17100" + }, + "BoundaryId": { + key: "service/dynamic/itis/s4l/Simulator/LF/Boundary", + version: "0.0.0", + label: "LF Boundary 1", + inputNodes: [ + "c104bb08-77b1-4157-b9f9-e9df7779df08" + ], + outputNode: false, + position: { + x: 100, + y: 250 + }, + parent: "89e185ca-dda1-4a45-8059-715f2cb17100" + }, + "SensorsId": { + key: "service/dynamic/itis/s4l/Simulator/LF/Sensors", + version: "0.0.0", + label: "LF Sensors 1", + inputNodes: [ + "c104bb08-77b1-4157-b9f9-e9df7779df08" + ], + outputNode: true, + position: { + x: 100, + y: 350 + }, + parent: "89e185ca-dda1-4a45-8059-715f2cb17100" + }, + "GridId": { + key: "service/dynamic/itis/s4l/Simulator/LF/Grid", + version: "0.0.0", + label: "LF Grid 1", + inputNodes: [ + "c104bb08-77b1-4157-b9f9-e9df7779df08" + ], + outputNode: false, + position: { + x: 100, + y: 450 + }, + parent: "89e185ca-dda1-4a45-8059-715f2cb17100" + }, + "VoxelId": { + key: "service/dynamic/itis/s4l/Simulator/LF/Voxel", + version: "0.0.0", + label: "LF Voxel 1", + inputNodes: [ + "c104bb08-77b1-4157-b9f9-e9df7779df08" + ], + outputNode: false, + position: { + x: 100, + y: 550 + }, + parent: "89e185ca-dda1-4a45-8059-715f2cb17100" + }, + "SolverSettingsId": { + key: "service/dynamic/itis/s4l/Simulator/LF/SolverSettings", + version: "0.0.0", + label: "LF SolverSett 1", + inputNodes: [], + outputNode: true, + position: { + x: 500, + y: 250 + }, + parent: "89e185ca-dda1-4a45-8059-715f2cb17100" + }, + "4069bf2e-e2be-4799-ad1c-c53f0cb46e4e": { + key: "service/computational/itis/Solver-LF", + version: "0.0.0", + label: "LF Solver 1", + inputs: { + inFile: { + nodeUuid: "89e185ca-dda1-4a45-8059-715f2cb17100", + output: "outFile" + } + }, + inputNodes: [ + "89e185ca-dda1-4a45-8059-715f2cb17100" + ], + position: { + x: 750, + y: 150 + } + } + } + }, { + projectUuid: "5a1d7405-882c-4611-a74c-4c75f3cf7749", + name: "LF Simulator expanded", + description: "LF Simulator expanded", + notes: "", + owner: "UUID-OF-ODEI", + collaborators: {}, + creationDate: "2018-08-31T12:44:03Z", + lastChangeDate: "2018-08-31T13:21:24Z", + thumbnail: "https://placeimg.com/171/96/tech/grayscale/?3.jpg", + workbench: { + "8870a55b-680d-41b4-b40c-c928cceb7d2a": { + key: "service/dynamic/itis/s4l/MaterialDB", + version: "0.0.0", + position: { + x: 10, + y: 160 + } + }, + "17a932a0-f401-4571-9c55-b579f5050d37": { + key: "service/dynamic/itis/s4l/Modeler", + version: "0.0.0", + position: { + x: 7, + y: 538 + } + }, + "83bc4123-ebe4-4f5f-8770-b1584d6cf95f": { + key: "service/dynamic/itis/s4l/Simulator/LF/Setup", + version: "0.0.0", + inputs: { + "frequency": 1000 + }, + position: { + x: 348, + y: 2 + } + }, + "ac80863e-e4ef-48c0-804b-d9296f1f3563": { + key: "service/dynamic/itis/s4l/Simulator/LF/Materials", + version: "0.0.0", + inputs: { + modeler: { + nodeUuid: "17a932a0-f401-4571-9c55-b579f5050d37", + output: "modeler" + }, + materialDB: { + nodeUuid: "8870a55b-680d-41b4-b40c-c928cceb7d2a", + output: "materialDB" + }, + "updateDispersive": false + }, + inputNodes: [ + "17a932a0-f401-4571-9c55-b579f5050d37", + "8870a55b-680d-41b4-b40c-c928cceb7d2a" + ], + position: { + x: 349, + y: 103 + } + }, + "ed4c85a8-c20f-4acd-8e1e-5161301e2f3d": { + key: "service/dynamic/itis/s4l/Simulator/LF/Boundary", + version: "0.0.0", + inputs: { + modeler: { + nodeUuid: "17a932a0-f401-4571-9c55-b579f5050d37", + output: "modeler" + }, + "boundarySetting": 3 + }, + position: { + x: 351, + y: 242 + } + }, + "36d70cf2-ef36-4052-988d-d32b3456b786": { + key: "service/dynamic/itis/s4l/Simulator/LF/Sensors", + version: "0.0.0", + inputs: { + modeler: { + nodeUuid: "17a932a0-f401-4571-9c55-b579f5050d37", + output: "modeler" + }, + "sensorSetting": 4 + }, + inputNodes: [ + "17a932a0-f401-4571-9c55-b579f5050d37" + ], + position: { + x: 353, + y: 363 + } + }, + "c3ab33a7-4ead-4302-9867-5b194a4f45ec": { + key: "service/dynamic/itis/s4l/Simulator/LF/Grid", + version: "0.0.0", + inputs: { + modeler: { + nodeUuid: "17a932a0-f401-4571-9c55-b579f5050d37", + output: "modeler" + }, + "materialSetting": { + nodeUuid: "ac80863e-e4ef-48c0-804b-d9296f1f3563", + output: "materialSetting" + }, + "boundarySetting": { + nodeUuid: "ed4c85a8-c20f-4acd-8e1e-5161301e2f3d", + output: "boundarySetting" + }, + "sensorSetting": { + nodeUuid: "36d70cf2-ef36-4052-988d-d32b3456b786", + output: "sensorSetting" + }, + "gridSetting": 5 + }, + inputNodes: [ + "17a932a0-f401-4571-9c55-b579f5050d37", + "ac80863e-e4ef-48c0-804b-d9296f1f3563", + "ed4c85a8-c20f-4acd-8e1e-5161301e2f3d", + "36d70cf2-ef36-4052-988d-d32b3456b786" + ], + position: { + x: 624, + y: 496 + } + }, + "01e28708-46c4-474b-837b-479fd596e566": { + key: "service/dynamic/itis/s4l/Simulator/LF/SolverSettings", + version: "0.0.0", + inputs: { + "setupSetting": { + nodeUuid: "83bc4123-ebe4-4f5f-8770-b1584d6cf95f", + output: "setupSetting" + }, + "voxelSetting": { + nodeUuid: "b37bea52-bb29-482a-9540-bc11c7dc779c", + output: "voxelSetting" + }, + "solverSetting": 7 + }, + inputNodes: [ + "83bc4123-ebe4-4f5f-8770-b1584d6cf95f", + "b37bea52-bb29-482a-9540-bc11c7dc779c" + ], + position: { + x: 955, + y: 318 + } + }, + "b37bea52-bb29-482a-9540-bc11c7dc779c": { + key: "service/dynamic/itis/s4l/Simulator/LF/Voxel", + version: "0.0.0", + inputs: { + modeler: { + nodeUuid: "17a932a0-f401-4571-9c55-b579f5050d37", + output: "modeler" + }, + "gridSetting": { + nodeUuid: "c3ab33a7-4ead-4302-9867-5b194a4f45ec", + output: "gridSetting" + }, + "voxelSetting": 6 + }, + inputNodes: [ + "17a932a0-f401-4571-9c55-b579f5050d37", + "c3ab33a7-4ead-4302-9867-5b194a4f45ec" + ], + position: { + x: 874, + y: 699 + } + }, + "2472a166-7a9e-4023-be12-465d2f6eee54": { + key: "service/computational/itis/Solver-LF", + version: "0.0.0", + inputs: { + "inFile": { + nodeUuid: "01e28708-46c4-474b-837b-479fd596e566", + output: "outFile" + } + }, + inputNodes: [ + "01e28708-46c4-474b-837b-479fd596e566" + ], + position: { + x: 1245, + y: 318 + } + } + } } ]; }, + + getProjectData: function(projectUuid) { + const projectList = this.getProjectList(); + for (let i = 0; i < projectList.length; i++) { + if (projectUuid === projectList[i].projectUuid) { + return projectList[i]; + } + } + return null; + }, + getUsername: function() { return "bizzy"; }, @@ -414,7 +916,8 @@ qx.Class.define("qxapp.dev.fake.Data", { outFile: { store: "s3-z43", path: "/bucket1/file1" - } + }, + outDir: null }, position: { x: 50, @@ -434,6 +937,10 @@ qx.Class.define("qxapp.dev.fake.Data", { "initial_WTstates.txt": { nodeUuid: "UUID5", output: "outFile" + }, + "initial_WTstates2.txt": { + nodeUuid: "UUID5", + output: "outFile" } }, outputs: { @@ -442,6 +949,9 @@ qx.Class.define("qxapp.dev.fake.Data", { "finalStates.txt": null, "vm_1Hz.txt": null }, + inputNodes: [ + "UUID5" + ], position: { x: 350, y: 100 @@ -461,6 +971,9 @@ qx.Class.define("qxapp.dev.fake.Data", { } }, outputs: {}, + inputNodes: [ + "UUID6" + ], position: { x: 700, y: 100 diff --git a/services/web/client/source/class/qxapp/theme/Color.js b/services/web/client/source/class/qxapp/theme/Color.js index 5dc3d91c222..135a072cdbc 100644 --- a/services/web/client/source/class/qxapp/theme/Color.js +++ b/services/web/client/source/class/qxapp/theme/Color.js @@ -12,7 +12,8 @@ qx.Theme.define("qxapp.theme.Color", { extend: osparc.theme.osparcdark.Color, colors: { - "workbench-link-active": "#777", + "workbench-link-comp-active": "#777", + "workbench-link-api-active": "#BBB", "workbench-link-selected": "#00F", "logger-debug-message": "#FFF", "logger-info-message": "#FFF", diff --git a/services/web/client/source/class/qxapp/theme/Font.js b/services/web/client/source/class/qxapp/theme/Font.js index de22e3b2b42..59898cb38fe 100644 --- a/services/web/client/source/class/qxapp/theme/Font.js +++ b/services/web/client/source/class/qxapp/theme/Font.js @@ -9,7 +9,14 @@ ************************************************************************ */ qx.Theme.define("qxapp.theme.Font", { - extend: qx.theme.indigo.Font, + extend: osparc.theme.osparcdark.Font, - fonts: {} + fonts: { + "nav-bar-label": { + size: 20, + family: ["Roboto"], + color: "text", + bold: true + } + } }); diff --git a/services/web/client/source/class/qxapp/wrappers/SvgWrapper.js b/services/web/client/source/class/qxapp/wrappers/SvgWrapper.js index f51cde28cfd..488fb9aa0eb 100644 --- a/services/web/client/source/class/qxapp/wrappers/SvgWrapper.js +++ b/services/web/client/source/class/qxapp/wrappers/SvgWrapper.js @@ -34,13 +34,13 @@ qx.Class.define("qxapp.wrappers.SvgWrapper", { svgPathPath ]); - dynLoader.addListenerOnce("ready", function(e) { + dynLoader.addListenerOnce("ready", e => { console.log(svgPath + " loaded"); this.setLibReady(true); this.fireDataEvent("SvgLibReady", true); }, this); - dynLoader.addListener("failed", function(e) { + dynLoader.addListener("failed", e => { let data = e.getData(); console.log("failed to load " + data.script); this.fireDataEvent("SvgLibReady", false); @@ -53,26 +53,24 @@ qx.Class.define("qxapp.wrappers.SvgWrapper", { return SVG(id); }, - drawCurve: function(draw, controls) { - const linkColor = qxapp.theme.Color.colors["workbench-link-active"]; + drawCurve: function(draw, controls, linkWidth = 3, portSphereDiameter = 4, arrowSize = 4) { + const linkColor = qxapp.theme.Color.colors["workbench-link-comp-active"]; let path = draw.path() .M(controls[0].x, controls[0].y) .C(controls[1], controls[2], controls[3]) .fill("none") .stroke({ - width: 3, + width: linkWidth, color: linkColor }); - const portSphereDiameter = 4; let marker1 = draw.marker(portSphereDiameter, portSphereDiameter, function(add) { add.circle(portSphereDiameter) .fill(linkColor); }); path.marker("start", marker1); - const arrowSize = 4; let marker2 = draw.marker(arrowSize, arrowSize, function(add) { add.path("M 0 0 V 4 L 2 2 Z") .fill(linkColor) @@ -85,6 +83,10 @@ qx.Class.define("qxapp.wrappers.SvgWrapper", { return path; }, + drawCurveMini: function(draw, controls) { + return this.drawCurve(draw, controls, 2); + }, + updateCurve: function(curve, controls) { if (curve.type === "path") { let mSegment = curve.getSegment(0); diff --git a/services/web/client/source/class/qxapp/wrappers/WebSocket.js b/services/web/client/source/class/qxapp/wrappers/WebSocket.js index 73d913152cd..9b4eed6c02a 100644 --- a/services/web/client/source/class/qxapp/wrappers/WebSocket.js +++ b/services/web/client/source/class/qxapp/wrappers/WebSocket.js @@ -124,7 +124,7 @@ qx.Class.define("qxapp.wrappers.WebSocket", { socketIOPath ]); - dynLoader.addListenerOnce("ready", function(e) { + dynLoader.addListenerOnce("ready", e => { console.log(socketIOPath + " loaded"); this.setLibReady(true); diff --git a/services/web/client/source/resource/qxapp/modelerMockup.png b/services/web/client/source/resource/qxapp/modelerMockup.png new file mode 100644 index 00000000000..f4566b9eb4b Binary files /dev/null and b/services/web/client/source/resource/qxapp/modelerMockup.png differ diff --git a/services/web/client/source/resource/qxapp/project-v0.0.1.json b/services/web/client/source/resource/qxapp/project-v0.0.1.json index 420c69ffb7f..521517252fa 100644 --- a/services/web/client/source/resource/qxapp/project-v0.0.1.json +++ b/services/web/client/source/resource/qxapp/project-v0.0.1.json @@ -5,6 +5,7 @@ "type": "object", "additionalProperties": false, "required": [ + "projectUuid", "name", "description", "notes", @@ -12,9 +13,18 @@ "collaborators", "creationDate", "lastChangeDate", + "thumbnail", "workbench" ], "properties": { + "projectUuid": { + "type": "string", + "description": "project unique identifier", + "examples": [ + "07640335-a91f-468c-ab69-a374fa82078d", + "9bcf8feb-c1b1-41b6-b201-639cd6ccdba8" + ] + }, "name": { "type": "string", "description": "project name", @@ -72,6 +82,13 @@ "2018-07-01T11:13:43Z" ] }, + "thumbnail": { + "type": "string", + "description": "url of the latest screenshot of the project", + "examples": [ + "https://placeimg.com/171/96/tech/grayscale/?0.jpg" + ] + }, "workbench": { "type": "object", "patternProperties": { @@ -185,6 +202,17 @@ } } }, + "links": { + "type": "array", + "items": { + "type": "string" + }, + "description": "node IDs of where the node is connected to", + "examples": [ + "nodeUuid1", + "nodeUuid2" + ] + }, "position": { "type": "object", "additionalProperties": false, diff --git a/services/web/server/docker/boot.sh b/services/web/server/docker/boot.sh old mode 100755 new mode 100644 diff --git a/services/web/server/src/simcore_service_webserver/comp_backend_api.py b/services/web/server/src/simcore_service_webserver/comp_backend_api.py index b7be275a5c2..b30d6967678 100644 --- a/services/web/server/src/simcore_service_webserver/comp_backend_api.py +++ b/services/web/server/src/simcore_service_webserver/comp_backend_api.py @@ -136,7 +136,7 @@ async def _parse_pipeline(pipeline_data): # pylint: disable=R0912 } # currently here a special case to handle the built-in file manager that should not be set as a task - if str(node_key).count("FileManager") == 0: + if str(node_key).count("FilePicker") == 0: # TODO: SAN This is temporary. As soon as the services are converted this should be removed. task = await api_converter.convert_task_to_old_version(task) # continue diff --git a/services/web/server/src/simcore_service_webserver/director_sdk.py b/services/web/server/src/simcore_service_webserver/director_sdk.py index 1bef007ac16..3869925c80a 100644 --- a/services/web/server/src/simcore_service_webserver/director_sdk.py +++ b/services/web/server/src/simcore_service_webserver/director_sdk.py @@ -34,7 +34,7 @@ _DIRECTOR_HOST = os.environ.get("DIRECTOR_HOST", "0.0.0.0") _DIRECTOR_PORT = os.environ.get("DIRECTOR_PORT", "8001") -_DIRECTOR_PATH = "v1" +_DIRECTOR_PATH = "v0" def get_director(): configuration = simcore_director_sdk.Configuration() diff --git a/services/web/server/src/simcore_service_webserver/registry_api.py b/services/web/server/src/simcore_service_webserver/registry_api.py index 0ff22c1d993..8d501ebe421 100644 --- a/services/web/server/src/simcore_service_webserver/registry_api.py +++ b/services/web/server/src/simcore_service_webserver/registry_api.py @@ -5,7 +5,6 @@ # pylint: disable=C0103 import logging -import async_timeout from aiohttp import web from simcore_director_sdk.rest import ApiException @@ -15,19 +14,9 @@ registry_routes = web.RouteTableDef() -async def async_request(method, session, url, data=None, timeout=10): - async with async_timeout.timeout(timeout): - if method == "GET": - async with session.get(url) as response: - return await response.json() - elif method == "POST": - async with session.post(url, json=data) as response: - return await response.json() - - -@registry_routes.get("/get_computational_services") -async def get_computational_services(request): +@registry_routes.get("/get_services") +async def get_services(request): """ --- description: This end-point returns a list of computational services. @@ -45,7 +34,7 @@ async def get_computational_services(request): try: director = director_sdk.get_director() - services = await director.services_get(service_type="computational") + services = await director.services_get() return web.json_response(services.to_dict()) except ApiException as exc: log.exception("Api Error while accessing director") diff --git a/services/web/server/src/simcore_service_webserver/sockets.py b/services/web/server/src/simcore_service_webserver/sockets.py index bb2473c12c6..6fd88e7beaa 100644 --- a/services/web/server/src/simcore_service_webserver/sockets.py +++ b/services/web/server/src/simcore_service_webserver/sockets.py @@ -28,22 +28,6 @@ def connect(sid, environ): interactive_services_manager.session_connect(sid) return True - -@SIO.on("getInteractiveServices") -async def get_interactive_services_handler(sid, data): - # pylint: disable=C0103 - # pylint: disable=W0613 - log.debug("client %s gets interactive services", sid) - try: - result = await interactive_services_manager.retrieve_list_of_services() - await SIO.emit("getInteractiveServices", data=result, room=sid) - #TODO: see how we handle errors back to the frontend - except IOError: - log.exception("Error emitting retrieved services") - except Exception: - log.exception("Error while retrieving interactive services") - - @SIO.on("startDynamic") async def start_dynamic_service(sid, data): log.debug("client %s starts dynamic service %s", sid, data)