├── .dockerignore ├── .github ├── actions │ └── publish_charts │ │ └── action.yaml └── workflows │ └── release.yaml ├── .gitignore ├── .pre-commit-config.yaml ├── .redocly.lint-ignore.yaml ├── .redocly.yaml ├── CONTRIBUTING.md ├── CONTRIBUTORS.md ├── LICENSE ├── NOTICE ├── README.md ├── agent_api ├── __init__.py ├── app.py ├── config │ ├── __init__.py │ ├── cloud.py │ ├── defaults.py │ ├── local.py │ ├── minikube.py │ └── test.py ├── endpoints │ ├── __init__.py │ └── v1 │ │ ├── __init__.py │ │ └── heartbeat.py ├── helpers │ ├── __init__.py │ └── health.py ├── routes │ ├── __init__.py │ └── v1_routes.py ├── schemas │ ├── __init__.py │ └── heartbeat.py └── tests │ ├── __init__.py │ └── integration │ ├── __init__.py │ └── v1_endpoints │ ├── __init__.py │ ├── conftest.py │ └── test_heartbeat.py ├── benchmark ├── README.md ├── cached_property.py └── requirements.txt ├── cli ├── README.md ├── __init__.py ├── __main__.py ├── base.py ├── entry_points │ ├── __init__.py │ ├── database_schema.py │ ├── dump_fixture.py │ ├── gen_events.py │ ├── graph_schema.py │ ├── init.py │ ├── load_fixture.py │ ├── migration_check.py │ ├── service_account_key.py │ ├── shell.py │ └── yoyo.py ├── graph_templates │ ├── body.html │ ├── head.html │ ├── rel.html │ └── tail.html ├── lib.py └── tests │ ├── __init__.py │ ├── entry_points │ ├── __init__.py │ ├── conftest.py │ └── test_init.py │ ├── test_imports.py │ └── test_lib.py ├── common ├── __init__.py ├── actions │ ├── __init__.py │ ├── action.py │ ├── action_factory.py │ ├── data_points.py │ ├── send_email_action.py │ └── webhook_action.py ├── api │ ├── __init__.py │ ├── base_view.py │ ├── flask_ext │ │ ├── __init__.py │ │ ├── authentication │ │ │ ├── __init__.py │ │ │ ├── common.py │ │ │ ├── jwt_plugin.py │ │ │ └── service_account_key_plugin.py │ │ ├── base_extension.py │ │ ├── config.py │ │ ├── cors.py │ │ ├── database_connection.py │ │ ├── exception_handling.py │ │ ├── health.py │ │ ├── htmx.py │ │ ├── logging.py │ │ ├── timing.py │ │ └── url_converters.py │ ├── request_parsing.py │ └── search_view.py ├── apscheduler_extensions.py ├── argparse.py ├── auth │ ├── __init__.py │ ├── keys │ │ ├── __init__.py │ │ ├── lib.py │ │ ├── service_key.py │ │ └── settings.py │ └── permissions.py ├── constants │ ├── __init__.py │ ├── defaults.py │ ├── email_templates.py │ ├── peewee.py │ ├── rbac.py │ ├── schema_limits.py │ ├── schema_validation.py │ └── validation_messages.py ├── datetime_utils.py ├── decorators.py ├── email │ ├── __init__.py │ ├── email_renderer.py │ ├── email_service.py │ └── templates │ │ ├── __init__.py │ │ ├── agent_status_change_template.py │ │ ├── base_template.py │ │ ├── instance_alert_template.py │ │ ├── message_log_template.py │ │ ├── metric_log_template.py │ │ ├── run_state_template.py │ │ ├── task_status_completed_template.py │ │ ├── task_status_error_template.py │ │ ├── task_status_missing_template.py │ │ ├── task_status_pending_template.py │ │ ├── task_status_started_template.py │ │ ├── task_status_warning_template.py │ │ └── test_status_template.py ├── entities │ ├── __init__.py │ ├── action.py │ ├── agent.py │ ├── alert.py │ ├── auth_provider.py │ ├── authentication.py │ ├── base_entity.py │ ├── company.py │ ├── component.py │ ├── component_meta.py │ ├── dataset.py │ ├── dataset_operation.py │ ├── event.py │ ├── instance.py │ ├── instance_rule.py │ ├── journey.py │ ├── organization.py │ ├── pipeline.py │ ├── project.py │ ├── rule.py │ ├── run.py │ ├── schedule.py │ ├── server.py │ ├── streaming_pipeline.py │ ├── task.py │ ├── test_outcome.py │ ├── testgen.py │ ├── upcoming_instance.py │ └── user.py ├── entity_services │ ├── __init__.py │ ├── agent_service.py │ ├── company_service.py │ ├── component_service.py │ ├── event_service.py │ ├── helpers │ │ ├── __init__.py │ │ ├── filter_rules.py │ │ └── list_rules.py │ ├── instance_dag_service.py │ ├── instance_service.py │ ├── journey_service.py │ ├── organization_service.py │ ├── pipeline_service.py │ ├── project_service.py │ ├── run_service.py │ ├── sa_key_service.py │ ├── test_outcome_service.py │ ├── upcoming_instance_service.py │ └── user_service.py ├── events │ ├── __init__.py │ ├── base.py │ ├── converters.py │ ├── enums.py │ ├── event_handler.py │ ├── internal │ │ ├── __init__.py │ │ ├── alert.py │ │ ├── scheduled_event.py │ │ ├── scheduled_instance.py │ │ └── system.py │ ├── v1 │ │ ├── ARCHITECTURE.md │ │ ├── __init__.py │ │ ├── dataset_operation_event.py │ │ ├── event.py │ │ ├── event_interface.py │ │ ├── event_schemas.py │ │ ├── message_log_event.py │ │ ├── metric_log_event.py │ │ ├── run_status_event.py │ │ ├── test_outcomes_event.py │ │ └── utils.py │ └── v2 │ │ ├── __init__.py │ │ ├── base.py │ │ ├── batch_pipeline_status.py │ │ ├── component_data.py │ │ ├── dataset_operation.py │ │ ├── helpers.py │ │ ├── message_log.py │ │ ├── metric_log.py │ │ ├── test_outcomes.py │ │ └── testgen.py ├── exceptions │ ├── __init__.py │ └── service.py ├── hash.py ├── join_helpers.py ├── json_encoder.py ├── kafka │ ├── __init__.py │ ├── consumer.py │ ├── errors.py │ ├── message.py │ ├── producer.py │ ├── settings.py │ └── topic.py ├── kubernetes │ ├── __init__.py │ └── readiness_probe.py ├── logging │ ├── __init__.py │ └── json_logging.py ├── messagepack.py ├── model.py ├── peewee_extensions │ ├── __init__.py │ ├── fields.py │ ├── fixtures.py │ └── templates │ │ └── model.toml ├── plugins.py ├── predicate_engine │ ├── __init__.py │ ├── _operators.py │ ├── compilers │ │ ├── __init__.py │ │ ├── simple_v1.py │ │ └── utils.py │ ├── exceptions.py │ ├── query.py │ └── schemas │ │ ├── __init__.py │ │ └── simple_v1.py ├── schemas │ ├── __init__.py │ ├── action_schemas.py │ ├── fields │ │ ├── __init__.py │ │ ├── cron_expr_str.py │ │ ├── enum_str.py │ │ ├── normalized_str.py │ │ └── zoneinfo.py │ ├── filter_schemas.py │ └── validators │ │ ├── __init__.py │ │ ├── not_empty.py │ │ └── regexp.py ├── sentinel.py ├── tests │ ├── __init__.py │ ├── fake_models │ │ ├── __init__.py │ │ ├── model_a.py │ │ └── model_b.py │ ├── integration │ │ ├── __init__.py │ │ ├── actions │ │ │ ├── __init__.py │ │ │ ├── test_action_factory.py │ │ │ ├── test_send_email_action.py │ │ │ └── test_webhook_action.py │ │ ├── api │ │ │ └── __init__.py │ │ ├── auth │ │ │ ├── __init__.py │ │ │ ├── conftest.py │ │ │ └── test_service_keys.py │ │ ├── conftest.py │ │ ├── email │ │ │ └── __init__.py │ │ ├── entities │ │ │ ├── __init__.py │ │ │ ├── conftest.py │ │ │ ├── test_action.py │ │ │ ├── test_alerts.py │ │ │ ├── test_base_entity.py │ │ │ ├── test_component_meta.py │ │ │ ├── test_dataset_operation.py │ │ │ ├── test_instance.py │ │ │ ├── test_instance_rules.py │ │ │ ├── test_pipelines.py │ │ │ ├── test_rule.py │ │ │ ├── test_runs.py │ │ │ ├── test_schedule.py │ │ │ ├── test_task.py │ │ │ ├── test_testgen.py │ │ │ ├── test_testgen_test_outcome_integration.py │ │ │ └── test_user.py │ │ ├── entity_services │ │ │ ├── __init__.py │ │ │ ├── conftest.py │ │ │ ├── test_company_service.py │ │ │ ├── test_component_service.py │ │ │ ├── test_event_service.py │ │ │ ├── test_instance_service.py │ │ │ ├── test_journey_service.py │ │ │ ├── test_organization_service.py │ │ │ ├── test_pipeline_service.py │ │ │ ├── test_project_service.py │ │ │ ├── test_run_service.py │ │ │ ├── test_test_outcome_service.py │ │ │ ├── test_upcoming_instance_services.py │ │ │ └── test_user_service.py │ │ ├── events │ │ │ ├── conftest.py │ │ │ ├── internal │ │ │ │ ├── test_alerts.py │ │ │ │ └── test_base.py │ │ │ ├── test_base_events.py │ │ │ └── test_handlers.py │ │ ├── flask_ext │ │ │ ├── __init__.py │ │ │ ├── conftest.py │ │ │ ├── test_cors.py │ │ │ ├── test_htmx.py │ │ │ └── test_service_account_auth.py │ │ ├── peewee_extensions │ │ │ ├── __init__.py │ │ │ ├── bad_fixtures │ │ │ │ ├── company.toml │ │ │ │ └── organization.toml │ │ │ ├── conftest.py │ │ │ ├── fixtures │ │ │ │ ├── company.toml │ │ │ │ ├── organization.toml │ │ │ │ ├── project.toml │ │ │ │ └── service-account-key.toml │ │ │ ├── test_fixture.py │ │ │ ├── test_json_dict_list_field.py │ │ │ ├── test_json_schema_field.py │ │ │ └── test_json_str_list_field.py │ │ ├── predicate_engine │ │ │ └── test_compilers_v1.py │ │ ├── test_apscheduler_extensions.py │ │ ├── test_config.py │ │ ├── test_health.py │ │ └── test_join_helpers.py │ └── unit │ │ ├── __init__.py │ │ ├── actions │ │ ├── __init__.py │ │ ├── conftest.py │ │ ├── test_action_factory.py │ │ ├── test_base_action.py │ │ ├── test_send_email_action.py │ │ └── test_webhook_action.py │ │ ├── api │ │ ├── __init__.py │ │ ├── conftest.py │ │ ├── test_auth_helpers.py │ │ ├── test_request_parsing.py │ │ └── test_search_view.py │ │ ├── auth │ │ ├── __init__.py │ │ └── test_auth_key_lib.py │ │ ├── constants │ │ ├── __init__.py │ │ ├── test_constants.py │ │ └── test_schema_validation.py │ │ ├── email │ │ ├── __init__.py │ │ └── test_email_service.py │ │ ├── entities │ │ ├── __init__.py │ │ ├── test_component_meta.py │ │ ├── test_journey_dag.py │ │ └── test_task.py │ │ ├── entity_services │ │ ├── __init__.py │ │ └── helpers │ │ │ ├── __init__.py │ │ │ ├── test_filter_rules.py │ │ │ └── test_list_rules.py │ │ ├── events │ │ ├── __init__.py │ │ ├── test_converters.py │ │ ├── v1 │ │ │ ├── __init__.py │ │ │ ├── conftest.py │ │ │ ├── test_base_events.py │ │ │ ├── test_close_run.py │ │ │ ├── test_dataset_operation_event.py │ │ │ ├── test_event_schemas.py │ │ │ ├── test_message_log.py │ │ │ ├── test_metric_log.py │ │ │ ├── test_status_event.py │ │ │ ├── test_testoutcomes.py │ │ │ └── test_testoutcomesitem.py │ │ └── v2 │ │ │ ├── conftest.py │ │ │ ├── test_batch_pipeline_status.py │ │ │ ├── test_dataset_operation.py │ │ │ ├── test_event.py │ │ │ ├── test_message_log.py │ │ │ ├── test_metric_log.py │ │ │ ├── test_test_outcomes.py │ │ │ └── test_testoutcomesitem.py │ │ ├── flask_ext │ │ ├── __init__.py │ │ ├── conftest.py │ │ ├── test_base_auth_plugin.py │ │ ├── test_cors.py │ │ ├── test_exception_handling.py │ │ └── test_jwt_plugin.py │ │ ├── kafka │ │ ├── __init__.py │ │ ├── conftest.py │ │ ├── test_consumer.py │ │ ├── test_producer.py │ │ └── test_topic.py │ │ ├── kubernetes │ │ ├── __init__.py │ │ └── test_readiness_probe.py │ │ ├── logging │ │ ├── __init__.py │ │ └── test_log_config.py │ │ ├── peewee_extensions │ │ ├── __init__.py │ │ ├── test_fixture.py │ │ └── test_peewee_extensions.py │ │ ├── predicate_engine │ │ ├── __init__.py │ │ ├── assertions.py │ │ ├── conftest.py │ │ ├── test_compilers_v1.py │ │ ├── test_predicate_engine.py │ │ └── test_schemas_v1.py │ │ ├── schemas │ │ ├── __init__.py │ │ ├── fields │ │ │ ├── __init__.py │ │ │ ├── test_cron_str.py │ │ │ ├── test_enum_str.py │ │ │ ├── test_normalized_str.py │ │ │ └── test_zoneinfo.py │ │ ├── test_filter_schemas.py │ │ └── validators │ │ │ ├── __init__.py │ │ │ ├── test_is_regexp.py │ │ │ └── test_not_empty.py │ │ ├── test_apscheduler_extensions.py │ │ ├── test_argparse.py │ │ ├── test_datetime_utils.py │ │ ├── test_decorators.py │ │ ├── test_hash.py │ │ ├── test_json_encoder.py │ │ ├── test_messagepack.py │ │ └── test_model_utils.py ├── typing.py ├── user_strings │ ├── __init__.py │ └── alert_descriptions.py └── validate_decorators_type_inference.pyi ├── conf ├── __init__.py ├── cloud.py ├── defaults.py ├── local.py ├── minikube.py └── test.py ├── conftest.py ├── deploy ├── charts │ ├── observability-app │ │ ├── Chart.yaml │ │ ├── templates │ │ │ ├── _environments.tpl │ │ │ ├── _helpers.tpl │ │ │ ├── _probes.tpl │ │ │ ├── agent-api.yaml │ │ │ ├── cli-tool-hook.yaml │ │ │ ├── event-api.yaml │ │ │ ├── observability-api.yaml │ │ │ ├── observability-ui.yaml │ │ │ ├── rules-engine.yaml │ │ │ ├── run-manager.yaml │ │ │ ├── scheduler.yaml │ │ │ └── serviceaccount.yaml │ │ └── values.yaml │ └── observability-services │ │ ├── Chart.lock │ │ ├── Chart.yaml │ │ └── values.yaml ├── charts_values │ ├── values-app-dev.yaml │ └── values-services-dev.yaml ├── conf │ ├── gunicorn.conf.py │ └── yoyo.ini ├── docker │ ├── docker-bake.json │ ├── observability-be.dockerfile │ └── observability-ui.dockerfile ├── generate_swagger_spec.py ├── migrations │ ├── 20240605_01_vjN7f-initial-schema.rollback.sql │ ├── 20240605_01_vjN7f-initial-schema.sql │ ├── 20240627_01_bgIWR-adding-agent-status-column.py │ ├── 20240627_02_ORQ6B-adding-agent-status-check-config-column.py │ ├── 20240627_03_4o7tH-agent-status-check-default-values.py │ ├── 20240701_01_zRe7i-add-project-alert-config-field.py │ ├── 20240705_01_37l4A-set-project-alert-config-default.py │ └── 20240723_01_K3c3Q-renaming-the-agent-check-interval-column.py ├── pages │ ├── deploy-pages.py │ └── index.html ├── promote_branch.sh ├── search_view_plugin.py └── subcomponent_plugin.py ├── event_api ├── __init__.py ├── app.py ├── config │ ├── __init__.py │ ├── cloud.py │ ├── defaults.py │ ├── local.py │ ├── minikube.py │ └── test.py ├── endpoints │ ├── __init__.py │ ├── v1 │ │ ├── __init__.py │ │ ├── dataset_operation.py │ │ ├── event_view.py │ │ ├── message_log.py │ │ ├── metric_log.py │ │ ├── run_status.py │ │ └── test_outcomes.py │ └── v2 │ │ ├── __init__.py │ │ ├── batch_pipeline_status.py │ │ ├── dataset_operation.py │ │ ├── event_view.py │ │ ├── message_log.py │ │ ├── metric_log.py │ │ └── test_outcomes.py ├── helpers │ ├── __init__.py │ └── health.py ├── routes │ ├── __init__.py │ ├── v1_routes.py │ └── v2_routes.py └── tests │ ├── __init__.py │ ├── integration │ ├── __init__.py │ ├── v1_endpoints │ │ ├── __init__.py │ │ ├── conftest.py │ │ ├── test_dataset_operation.py │ │ ├── test_event_view.py │ │ ├── test_message_log.py │ │ ├── test_metric_log.py │ │ ├── test_run_status.py │ │ └── test_testoutcomes.py │ └── v2_endpoints │ │ ├── __init__.py │ │ ├── conftest.py │ │ ├── test_batch_pipeline_status.py │ │ ├── test_dataset_operation.py │ │ ├── test_message_log.py │ │ ├── test_metric_log.py │ │ └── test_test_outcomes.py │ └── unit │ └── __init__.py ├── fixtures └── README.md ├── observability_api ├── README.md ├── __init__.py ├── app.py ├── config │ ├── __init__.py │ ├── cloud.py │ ├── defaults.py │ ├── local.py │ ├── minikube.py │ └── test.py ├── endpoints │ ├── __init__.py │ ├── component_view.py │ ├── entity_view.py │ └── v1 │ │ ├── __init__.py │ │ ├── actions.py │ │ ├── agents.py │ │ ├── alerts.py │ │ ├── auth.py │ │ ├── batch_pipelines.py │ │ ├── companies.py │ │ ├── components.py │ │ ├── datasets.py │ │ ├── instance_rules.py │ │ ├── instances.py │ │ ├── journeys.py │ │ ├── organizations.py │ │ ├── project_settings.py │ │ ├── projects.py │ │ ├── rules.py │ │ ├── runs.py │ │ ├── schedules.py │ │ ├── servers.py │ │ ├── service_account_keys.py │ │ ├── streaming_pipelines.py │ │ ├── tasks.py │ │ ├── test_outcomes.py │ │ ├── upcoming_instances.py │ │ └── users.py ├── helpers │ ├── __init__.py │ └── health.py ├── routes │ ├── __init__.py │ └── v1_routes.py ├── schemas │ ├── __init__.py │ ├── action_schemas.py │ ├── agent_schemas.py │ ├── alert_schemas.py │ ├── base_schemas.py │ ├── company_schemas.py │ ├── component_schemas.py │ ├── dataset_schemas.py │ ├── event_schemas.py │ ├── instance_dag_schemas.py │ ├── instance_rule_schemas.py │ ├── instance_schemas.py │ ├── journey_dag_schemas.py │ ├── journey_schemas.py │ ├── organization_schemas.py │ ├── pipeline_schemas.py │ ├── project_schemas.py │ ├── rule_schemas.py │ ├── run_schemas.py │ ├── schedule_schemas.py │ ├── server_schemas.py │ ├── service_account_key_schemas.py │ ├── streaming_pipeline_schemas.py │ ├── task_schemas.py │ ├── testgen_dataset_component_schemas.py │ ├── testgen_test_outcome_schemas.py │ ├── upcoming_instance_schemas.py │ └── user_schemas.py └── tests │ ├── __init__.py │ ├── functional │ └── __init__.py │ ├── integration │ ├── __init__.py │ ├── helpers │ │ └── __init__.py │ ├── schemas │ │ ├── __init__.py │ │ ├── conftest.py │ │ ├── test_agent_schemas.py │ │ ├── test_alert_schemas.py │ │ ├── test_event_schemas.py │ │ ├── test_testgen_component_schemas.py │ │ └── test_testgen_test_outcome_schemas.py │ └── v1_endpoints │ │ ├── __init__.py │ │ ├── conftest.py │ │ ├── test_actions.py │ │ ├── test_agents.py │ │ ├── test_alerts.py │ │ ├── test_basic_auth.py │ │ ├── test_batch_pipelines.py │ │ ├── test_companies.py │ │ ├── test_components.py │ │ ├── test_converters.py │ │ ├── test_instance_rules.py │ │ ├── test_instances.py │ │ ├── test_journeys.py │ │ ├── test_jwt_auth.py │ │ ├── test_organizations.py │ │ ├── test_project_settings.py │ │ ├── test_projects.py │ │ ├── test_route_auth.py │ │ ├── test_rules.py │ │ ├── test_runs.py │ │ ├── test_sa_key_auth.py │ │ ├── test_schedules.py │ │ ├── test_service_account_keys.py │ │ ├── test_tasks.py │ │ ├── test_test_outcomes.py │ │ ├── test_upcoming_instances.py │ │ └── test_users.py │ └── unit │ ├── __init__.py │ ├── helpers │ └── __init__.py │ ├── schemas │ ├── test_instance_dag_schema.py │ ├── test_instance_rule_schema.py │ ├── test_operations_summary_schema.py │ ├── test_rule_schema.py │ ├── test_schedule_schema.py │ ├── test_service_account_key_schema.py │ ├── test_test_outcome_schema.py │ ├── test_testgen_test_outcome_integration_schemas.py │ └── test_upcoming_instance_schemas.py │ └── v1_endpoints │ ├── __init__.py │ ├── conftest.py │ ├── test_organizations.py │ ├── test_projects.py │ ├── test_service_account_keys.py │ └── test_users.py ├── observability_ui ├── .editorconfig ├── .eslintrc.json ├── .prettierignore ├── .prettierrc ├── .yarn │ └── releases │ │ └── yarn-1.22.21.cjs ├── .yarnrc ├── README.md ├── apps │ ├── .gitkeep │ ├── basic-auth │ │ ├── .eslintrc.json │ │ ├── jest.config.ts │ │ ├── module-federation.config.js │ │ ├── package.json │ │ ├── project.json │ │ ├── src │ │ │ ├── app │ │ │ │ ├── app.component.ts │ │ │ │ ├── app.module.ts │ │ │ │ ├── app.routes.ts │ │ │ │ ├── authentication │ │ │ │ │ ├── authentication.component.ts │ │ │ │ │ ├── authentication.module.ts │ │ │ │ │ └── authentication.routes.ts │ │ │ │ ├── login │ │ │ │ │ ├── login.component.html │ │ │ │ │ ├── login.component.scss │ │ │ │ │ ├── login.component.spec.ts │ │ │ │ │ └── login.component.ts │ │ │ │ ├── logout │ │ │ │ │ ├── logout.component.html │ │ │ │ │ ├── logout.component.scss │ │ │ │ │ ├── logout.component.spec.ts │ │ │ │ │ └── logout.component.ts │ │ │ │ └── services │ │ │ │ │ └── auth.service.ts │ │ │ ├── assets │ │ │ │ ├── .gitkeep │ │ │ │ └── dk-logo-horizontal.svg │ │ │ ├── bootstrap.ts │ │ │ ├── favicon.ico │ │ │ ├── index.html │ │ │ ├── main.ts │ │ │ ├── styles.scss │ │ │ └── test-setup.ts │ │ ├── tsconfig.app.json │ │ ├── tsconfig.editor.json │ │ ├── tsconfig.json │ │ ├── tsconfig.spec.json │ │ ├── webpack.config.js │ │ └── webpack.prod.config.js │ └── shell │ │ ├── .eslintrc.json │ │ ├── jest.config.ts │ │ ├── module-federation.config.js │ │ ├── ngsw-config.json │ │ ├── package.json │ │ ├── project.json │ │ ├── src │ │ ├── app │ │ │ ├── app-routing.module.ts │ │ │ ├── app-version │ │ │ │ ├── app-version.component.css │ │ │ │ ├── app-version.component.html │ │ │ │ ├── app-version.component.spec.ts │ │ │ │ ├── app-version.component.ts │ │ │ │ ├── app-version.module.ts │ │ │ │ ├── app-version.service.spec.ts │ │ │ │ └── app-version.service.ts │ │ │ ├── app.component.html │ │ │ ├── app.component.scss │ │ │ ├── app.component.spec.ts │ │ │ ├── app.component.ts │ │ │ ├── app.module.ts │ │ │ ├── components │ │ │ │ ├── default-error-handler │ │ │ │ │ ├── default-error-handler.component.spec.ts │ │ │ │ │ ├── default-error-handler.component.ts │ │ │ │ │ ├── default-error-handler.module.ts │ │ │ │ │ ├── default-error.handler.spec.ts │ │ │ │ │ └── default-error.handler.ts │ │ │ │ ├── email-action │ │ │ │ │ ├── email-action.component.html │ │ │ │ │ ├── email-action.component.scss │ │ │ │ │ ├── email-action.component.ts │ │ │ │ │ └── email-action.store.ts │ │ │ │ ├── entry │ │ │ │ │ ├── entry.component.spec.ts │ │ │ │ │ └── entry.component.ts │ │ │ │ ├── header │ │ │ │ │ ├── header.component.html │ │ │ │ │ ├── header.component.scss │ │ │ │ │ ├── header.component.spec.ts │ │ │ │ │ └── header.component.ts │ │ │ │ ├── offline │ │ │ │ │ ├── offline.component.html │ │ │ │ │ ├── offline.component.scss │ │ │ │ │ ├── offline.component.spec.ts │ │ │ │ │ └── offline.component.ts │ │ │ │ ├── project-alerts │ │ │ │ │ ├── project-alerts.component.html │ │ │ │ │ ├── project-alerts.component.scss │ │ │ │ │ ├── project-alerts.component.spec.ts │ │ │ │ │ ├── project-alerts.component.ts │ │ │ │ │ ├── project-alerts.store.spec.ts │ │ │ │ │ └── project-alerts.store.ts │ │ │ │ ├── rules-actions │ │ │ │ │ ├── abstract.rule.spec.ts │ │ │ │ │ ├── abstract.rule.ts │ │ │ │ │ ├── action │ │ │ │ │ │ ├── action-template.component.html │ │ │ │ │ │ ├── action-template.component.scss │ │ │ │ │ │ ├── action-template.component.spec.ts │ │ │ │ │ │ └── action-template.component.ts │ │ │ │ │ ├── alert │ │ │ │ │ │ ├── templating-alert.component.scss │ │ │ │ │ │ ├── templating-alert.component.spec.ts │ │ │ │ │ │ └── templating-alert.component.ts │ │ │ │ │ ├── implementations │ │ │ │ │ │ ├── actions │ │ │ │ │ │ │ ├── example │ │ │ │ │ │ │ │ └── example-action.component.ts │ │ │ │ │ │ │ ├── send-email │ │ │ │ │ │ │ │ ├── send-email-action.component.spec.ts │ │ │ │ │ │ │ │ └── send-email-action.component.ts │ │ │ │ │ │ │ └── webhook │ │ │ │ │ │ │ │ ├── webhook-action.component.spec.ts │ │ │ │ │ │ │ │ └── webhook-action.component.ts │ │ │ │ │ │ └── rules │ │ │ │ │ │ │ ├── example │ │ │ │ │ │ │ ├── example-rule-label.component.ts │ │ │ │ │ │ │ └── example-rule.component.ts │ │ │ │ │ │ │ ├── instance-has-alert │ │ │ │ │ │ │ ├── instance-has-alert-rule.component.spec.ts │ │ │ │ │ │ │ └── instance-has-alert-rule.component.ts │ │ │ │ │ │ │ ├── message-log │ │ │ │ │ │ │ ├── message-log-rule.component.spec.ts │ │ │ │ │ │ │ └── message-log-rule.component.ts │ │ │ │ │ │ │ ├── metric-log │ │ │ │ │ │ │ ├── metric-log-rule.component.spec.ts │ │ │ │ │ │ │ └── metric-log-rule.component.ts │ │ │ │ │ │ │ ├── run-state │ │ │ │ │ │ │ ├── run-state-rule.component.scss │ │ │ │ │ │ │ ├── run-state-rule.component.spec.ts │ │ │ │ │ │ │ └── run-state-rule.component.ts │ │ │ │ │ │ │ ├── task-status │ │ │ │ │ │ │ ├── task-status-rule.component.spec.ts │ │ │ │ │ │ │ └── task-status-rule.component.ts │ │ │ │ │ │ │ └── test-status │ │ │ │ │ │ │ ├── test-status-rule.component.spec.ts │ │ │ │ │ │ │ └── test-status-rule.component.ts │ │ │ │ │ ├── label │ │ │ │ │ │ ├── templating-label.component.spec.ts │ │ │ │ │ │ └── templating-label.component.ts │ │ │ │ │ ├── rule-display │ │ │ │ │ │ ├── rule-display.component.html │ │ │ │ │ │ ├── rule-display.component.scss │ │ │ │ │ │ ├── rule-display.component.spec.ts │ │ │ │ │ │ └── rule-display.component.ts │ │ │ │ │ ├── rule.model.ts │ │ │ │ │ ├── rule.service.spec.ts │ │ │ │ │ ├── rule.service.ts │ │ │ │ │ ├── rule.store.spec.ts │ │ │ │ │ ├── rule.store.ts │ │ │ │ │ └── rules-actions.module.ts │ │ │ │ ├── sidenav-menu │ │ │ │ │ ├── sidenav-menu.component.html │ │ │ │ │ ├── sidenav-menu.component.scss │ │ │ │ │ ├── sidenav-menu.component.spec.ts │ │ │ │ │ ├── sidenav-menu.component.ts │ │ │ │ │ └── sidenav-menu.model.ts │ │ │ │ ├── summary-item │ │ │ │ │ ├── summary-item.component.html │ │ │ │ │ ├── summary-item.component.scss │ │ │ │ │ ├── summary-item.component.spec.ts │ │ │ │ │ └── summary-item.component.ts │ │ │ │ └── summary │ │ │ │ │ ├── summary.component.html │ │ │ │ │ ├── summary.component.scss │ │ │ │ │ ├── summary.component.spec.ts │ │ │ │ │ └── summary.component.ts │ │ │ ├── config.ts │ │ │ ├── core.translation.ts │ │ │ ├── guards │ │ │ │ ├── is-online.guard.spec.ts │ │ │ │ └── is-online.guard.ts │ │ │ ├── projects │ │ │ │ ├── api-keys │ │ │ │ │ ├── add-api-key-modal │ │ │ │ │ │ ├── add-api-key-modal.component.html │ │ │ │ │ │ ├── add-api-key-modal.component.scss │ │ │ │ │ │ ├── add-api-key-modal.component.spec.ts │ │ │ │ │ │ └── add-api-key-modal.component.ts │ │ │ │ │ ├── api-keys.component.html │ │ │ │ │ ├── api-keys.component.scss │ │ │ │ │ ├── api-keys.component.spec.ts │ │ │ │ │ ├── api-keys.component.ts │ │ │ │ │ ├── api-keys.service.spec.ts │ │ │ │ │ ├── api-keys.service.ts │ │ │ │ │ ├── api-keys.store.spec.ts │ │ │ │ │ ├── api-keys.store.ts │ │ │ │ │ └── delete-keys-modal │ │ │ │ │ │ ├── delete-key-modal.component.ts │ │ │ │ │ │ └── delete-keys-modal.component.spec.ts │ │ │ │ ├── component-panel │ │ │ │ │ ├── component-panel.component.html │ │ │ │ │ ├── component-panel.component.spec.ts │ │ │ │ │ ├── component-panel.component.ts │ │ │ │ │ ├── component-panel.module.ts │ │ │ │ │ ├── component-panel.translation.ts │ │ │ │ │ ├── component.panel.component.scss │ │ │ │ │ └── delete-component-dialog │ │ │ │ │ │ ├── delete-component-dialog.component.spec.ts │ │ │ │ │ │ └── delete-component-dialog.component.ts │ │ │ │ ├── components │ │ │ │ │ ├── add-component-dialog │ │ │ │ │ │ ├── add-component-dialog.component.html │ │ │ │ │ │ ├── add-component-dialog.component.scss │ │ │ │ │ │ ├── add-component-dialog.component.spec.ts │ │ │ │ │ │ ├── add-component-dialog.component.ts │ │ │ │ │ │ └── add-component-dialog.translation.ts │ │ │ │ │ ├── component-icon │ │ │ │ │ │ ├── component-icon.component.spec.ts │ │ │ │ │ │ └── component-icon.component.ts │ │ │ │ │ ├── components-list │ │ │ │ │ │ ├── component-list.translation.ts │ │ │ │ │ │ ├── components-list.component.html │ │ │ │ │ │ ├── components-list.component.scss │ │ │ │ │ │ ├── components-list.component.spec.ts │ │ │ │ │ │ └── components-list.component.ts │ │ │ │ │ ├── components-routing.module.ts │ │ │ │ │ ├── components.module.ts │ │ │ │ │ ├── components.store.spec.ts │ │ │ │ │ ├── components.store.ts │ │ │ │ │ ├── multiple-delete-dialog │ │ │ │ │ │ ├── multiple-delete-dialog.component.scss │ │ │ │ │ │ ├── multiple-delete-dialog.component.spec.ts │ │ │ │ │ │ └── multiple-delete-dialog.component.ts │ │ │ │ │ └── multiple-journey-dialog.component.ts │ │ │ │ │ │ ├── multiple-journey-dialog.component.scss │ │ │ │ │ │ ├── multiple-journey-dialog.component.spec.ts │ │ │ │ │ │ └── multiple-journey-dialog.component.ts │ │ │ │ ├── edit-expected-arrival-window │ │ │ │ │ ├── edit-expected-arrival-window.component.html │ │ │ │ │ └── edit-expected-arrival-window.component.ts │ │ │ │ ├── edit-expected-schedule │ │ │ │ │ ├── edit-expected-schedule.component.html │ │ │ │ │ └── edit-expected-schedule.component.ts │ │ │ │ ├── events │ │ │ │ │ ├── batch-runs │ │ │ │ │ │ ├── batch-runs.component.html │ │ │ │ │ │ ├── batch-runs.component.scss │ │ │ │ │ │ ├── batch-runs.component.spec.ts │ │ │ │ │ │ └── batch-runs.component.ts │ │ │ │ │ ├── event-list │ │ │ │ │ │ ├── event-list.component.html │ │ │ │ │ │ ├── event-list.component.scss │ │ │ │ │ │ ├── event-list.component.spec.ts │ │ │ │ │ │ └── event-list.component.ts │ │ │ │ │ ├── events-routing.module.ts │ │ │ │ │ ├── events.component.html │ │ │ │ │ ├── events.component.scss │ │ │ │ │ ├── events.component.spec.ts │ │ │ │ │ ├── events.component.ts │ │ │ │ │ └── events.module.ts │ │ │ │ ├── instances │ │ │ │ │ ├── alerts-dialog │ │ │ │ │ │ ├── alerts-dialog.component.html │ │ │ │ │ │ ├── alerts-dialog.component.scss │ │ │ │ │ │ ├── alerts-dialog.component.spec.ts │ │ │ │ │ │ └── alerts-dialog.component.ts │ │ │ │ │ ├── instance-alerts │ │ │ │ │ │ ├── instance-alerts.component.html │ │ │ │ │ │ ├── instance-alerts.component.scss │ │ │ │ │ │ ├── instance-alerts.component.spec.ts │ │ │ │ │ │ └── instance-alerts.component.ts │ │ │ │ │ ├── instance-details │ │ │ │ │ │ ├── instance-details.component.html │ │ │ │ │ │ ├── instance-details.component.scss │ │ │ │ │ │ ├── instance-details.component.spec.ts │ │ │ │ │ │ └── instance-details.component.ts │ │ │ │ │ ├── instance-events │ │ │ │ │ │ ├── instance-events.component.html │ │ │ │ │ │ ├── instance-events.component.scss │ │ │ │ │ │ ├── instance-events.component.spec.ts │ │ │ │ │ │ └── instance-events.component.ts │ │ │ │ │ ├── instance-runs-summary │ │ │ │ │ │ ├── instance-runs-summary.component.html │ │ │ │ │ │ ├── instance-runs-summary.component.scss │ │ │ │ │ │ ├── instance-runs-summary.component.spec.ts │ │ │ │ │ │ └── instance-runs-summary.component.ts │ │ │ │ │ ├── instance-runs │ │ │ │ │ │ ├── instance-runs.component.html │ │ │ │ │ │ ├── instance-runs.component.scss │ │ │ │ │ │ ├── instance-runs.component.spec.ts │ │ │ │ │ │ └── instance-runs.component.ts │ │ │ │ │ ├── instance-status │ │ │ │ │ │ ├── instance-status.component.html │ │ │ │ │ │ ├── instance-status.component.scss │ │ │ │ │ │ ├── instance-status.component.spec.ts │ │ │ │ │ │ └── instance-status.component.ts │ │ │ │ │ ├── instance-tests │ │ │ │ │ │ ├── instance-tests.component.html │ │ │ │ │ │ ├── instance-tests.component.scss │ │ │ │ │ │ ├── instance-tests.component.spec.ts │ │ │ │ │ │ └── instance-tests.component.ts │ │ │ │ │ ├── instance-timeline │ │ │ │ │ │ ├── instance-timeline.component.html │ │ │ │ │ │ ├── instance-timeline.component.scss │ │ │ │ │ │ ├── instance-timeline.component.spec.ts │ │ │ │ │ │ └── instance-timeline.component.ts │ │ │ │ │ ├── instances-list │ │ │ │ │ │ ├── instances-list.component.html │ │ │ │ │ │ ├── instances-list.component.scss │ │ │ │ │ │ ├── instances-list.component.spec.ts │ │ │ │ │ │ └── instances-list.component.ts │ │ │ │ │ ├── instances-routing.module.ts │ │ │ │ │ ├── instances.module.ts │ │ │ │ │ └── instances.translation.ts │ │ │ │ ├── integrations │ │ │ │ │ ├── integrations-panel │ │ │ │ │ │ ├── integrations-panel.component.html │ │ │ │ │ │ ├── integrations-panel.component.scss │ │ │ │ │ │ ├── integrations-panel.component.spec.ts │ │ │ │ │ │ └── integrations-panel.component.ts │ │ │ │ │ ├── integrations-routing.module.ts │ │ │ │ │ ├── integrations.component.html │ │ │ │ │ ├── integrations.component.scss │ │ │ │ │ ├── integrations.component.spec.ts │ │ │ │ │ ├── integrations.component.ts │ │ │ │ │ ├── integrations.model.ts │ │ │ │ │ ├── integrations.module.ts │ │ │ │ │ ├── integrations.translations.ts │ │ │ │ │ ├── service-key-form │ │ │ │ │ │ ├── service-key-form.component.spec.ts │ │ │ │ │ │ └── service-key-form.component.ts │ │ │ │ │ ├── tool-selector │ │ │ │ │ │ ├── get-tool-class.pipe.spec.ts │ │ │ │ │ │ ├── get-tool-class.pipe.ts │ │ │ │ │ │ ├── tool-selector.component.spec.ts │ │ │ │ │ │ └── tool-selector.component.ts │ │ │ │ │ └── tools │ │ │ │ │ │ ├── abstract-tool.directive.spec.ts │ │ │ │ │ │ ├── abstract-tool.directive.ts │ │ │ │ │ │ ├── agent-script-v2.tpl │ │ │ │ │ │ ├── agent-script.tpl │ │ │ │ │ │ ├── airflow-tool │ │ │ │ │ │ ├── airflow-tool.component.html │ │ │ │ │ │ ├── airflow-tool.component.spec.ts │ │ │ │ │ │ └── airflow-tool.component.ts │ │ │ │ │ │ ├── aws-sqs-tool │ │ │ │ │ │ ├── aws-sqs-tool.component.html │ │ │ │ │ │ ├── aws-sqs-tool.component.spec.ts │ │ │ │ │ │ └── aws-sqs-tool.component.ts │ │ │ │ │ │ ├── azure-blob-storage-tool │ │ │ │ │ │ ├── azure-blob-storage-tool.component.html │ │ │ │ │ │ ├── azure-blob-storage-tool.component.spec.ts │ │ │ │ │ │ └── azure-blob-storage-tool.component.ts │ │ │ │ │ │ ├── azure-datafactory-tool │ │ │ │ │ │ ├── azure-datafactory-tool.component.html │ │ │ │ │ │ ├── azure-datafactory-tool.component.spec.ts │ │ │ │ │ │ └── azure-datafactory-tool.component.ts │ │ │ │ │ │ ├── azure-functions-tool │ │ │ │ │ │ ├── azure-functions-tool.component.html │ │ │ │ │ │ ├── azure-functions-tool.component.spec.ts │ │ │ │ │ │ └── azure-functions-tool.component.ts │ │ │ │ │ │ ├── azure-synapse-pipelines-tool │ │ │ │ │ │ ├── azure-synapse-pipelines-tool.component.html │ │ │ │ │ │ ├── azure-synapse-pipelines-tool.component.spec.ts │ │ │ │ │ │ └── azure-synapse-pipelines-tool.component.ts │ │ │ │ │ │ ├── cloud-composer-tool │ │ │ │ │ │ ├── cloud-composer-tool.component.html │ │ │ │ │ │ ├── cloud-composer-tool.component.spec.ts │ │ │ │ │ │ └── cloud-composer-tool.component.ts │ │ │ │ │ │ ├── databricks-tool │ │ │ │ │ │ ├── databricks-tool.component.html │ │ │ │ │ │ ├── databricks-tool.component.spec.ts │ │ │ │ │ │ └── databricks-tool.component.ts │ │ │ │ │ │ ├── dbt-core-tool │ │ │ │ │ │ ├── dbt-core-tool.component.html │ │ │ │ │ │ ├── dbt-core-tool.component.spec.ts │ │ │ │ │ │ └── dbt-core-tool.component.ts │ │ │ │ │ │ ├── fivetran-logs-tool │ │ │ │ │ │ ├── fivetran-logs-tool.component.html │ │ │ │ │ │ ├── fivetran-logs-tool.component.spec.ts │ │ │ │ │ │ └── fivetran-logs-tool.component.ts │ │ │ │ │ │ ├── power-bi-tool │ │ │ │ │ │ ├── power-bi-tool.component.html │ │ │ │ │ │ ├── power-bi-tool.component.spec.ts │ │ │ │ │ │ └── power-bi-tool.component.ts │ │ │ │ │ │ ├── qlik-tool │ │ │ │ │ │ ├── qlik-tool.component.html │ │ │ │ │ │ ├── qlik-tool.component.spec.ts │ │ │ │ │ │ └── qlik-tool.component.ts │ │ │ │ │ │ ├── ssis-tool │ │ │ │ │ │ ├── ssis-tool.component.html │ │ │ │ │ │ ├── ssis-tool.component.spec.ts │ │ │ │ │ │ └── ssis-tool.component.ts │ │ │ │ │ │ ├── talend-tool │ │ │ │ │ │ ├── talend-tool.component.html │ │ │ │ │ │ ├── talend-tool.component.spec.ts │ │ │ │ │ │ └── talend-tool.component.ts │ │ │ │ │ │ ├── tool-display.component.scss │ │ │ │ │ │ ├── tool-display.component.spec.ts │ │ │ │ │ │ ├── tool-display.component.ts │ │ │ │ │ │ └── tools-common.scss │ │ │ │ ├── journey-dag-legend │ │ │ │ │ ├── journey-dag-legend.component.scss │ │ │ │ │ └── journey-dag-legend.component.ts │ │ │ │ ├── journeys │ │ │ │ │ ├── add-journey-dialog │ │ │ │ │ │ ├── add-journey-dialog.component.html │ │ │ │ │ │ ├── add-journey-dialog.component.scss │ │ │ │ │ │ ├── add-journey-dialog.component.spec.ts │ │ │ │ │ │ └── add-journey-dialog.component.ts │ │ │ │ │ ├── journey-details │ │ │ │ │ │ ├── journey-details.component.html │ │ │ │ │ │ ├── journey-details.component.scss │ │ │ │ │ │ ├── journey-details.component.spec.ts │ │ │ │ │ │ └── journey-details.component.ts │ │ │ │ │ ├── journey-instance-rules │ │ │ │ │ │ ├── journey-instance-rules.component.html │ │ │ │ │ │ ├── journey-instance-rules.component.scss │ │ │ │ │ │ ├── journey-instance-rules.component.spec.ts │ │ │ │ │ │ └── journey-instance-rules.component.ts │ │ │ │ │ ├── journey-relationships │ │ │ │ │ │ ├── journey-relationships.component.html │ │ │ │ │ │ ├── journey-relationships.component.scss │ │ │ │ │ │ ├── journey-relationships.component.spec.ts │ │ │ │ │ │ └── journey-relationships.component.ts │ │ │ │ │ ├── journey-rules │ │ │ │ │ │ ├── journey-rules.component.html │ │ │ │ │ │ ├── journey-rules.component.scss │ │ │ │ │ │ ├── journey-rules.component.spec.ts │ │ │ │ │ │ └── journey-rules.component.ts │ │ │ │ │ ├── journey-settings │ │ │ │ │ │ ├── journey-settings.component.html │ │ │ │ │ │ ├── journey-settings.component.scss │ │ │ │ │ │ ├── journey-settings.component.spec.ts │ │ │ │ │ │ └── journey-settings.component.ts │ │ │ │ │ ├── journeys-list │ │ │ │ │ │ ├── journeys-list.component.html │ │ │ │ │ │ ├── journeys-list.component.scss │ │ │ │ │ │ ├── journeys-list.component.spec.ts │ │ │ │ │ │ └── journeys-list.component.ts │ │ │ │ │ ├── journeys-routing.module.ts │ │ │ │ │ ├── journeys.module.ts │ │ │ │ │ ├── journeys.store.spec.ts │ │ │ │ │ ├── journeys.store.ts │ │ │ │ │ ├── journeys.translation.ts │ │ │ │ │ └── no-components-dialog │ │ │ │ │ │ ├── no-components-dialog.component.scss │ │ │ │ │ │ ├── no-components-dialog.component.spec.ts │ │ │ │ │ │ └── no-components-dialog.component.ts │ │ │ │ ├── multiple-component-panel │ │ │ │ │ ├── multiple-component-panel.component.html │ │ │ │ │ ├── multiple-component-panel.component.scss │ │ │ │ │ ├── multiple-component-panel.component.spec.ts │ │ │ │ │ └── multiple-component-panel.component.ts │ │ │ │ ├── overview │ │ │ │ │ ├── overview.component.html │ │ │ │ │ ├── overview.component.scss │ │ │ │ │ ├── overview.component.spec.ts │ │ │ │ │ └── overview.component.ts │ │ │ │ ├── project-display │ │ │ │ │ ├── project-display.component.scss │ │ │ │ │ ├── project-display.component.spec.ts │ │ │ │ │ └── project-display.component.ts │ │ │ │ ├── projects.menu.model.ts │ │ │ │ ├── projects.module.ts │ │ │ │ ├── projects.translation.ts │ │ │ │ ├── runs-table │ │ │ │ │ └── runs-table.module.ts │ │ │ │ ├── runs │ │ │ │ │ ├── events-table │ │ │ │ │ │ ├── events-table.component.html │ │ │ │ │ │ ├── events-table.component.scss │ │ │ │ │ │ ├── events-table.component.spec.ts │ │ │ │ │ │ └── events-table.component.ts │ │ │ │ │ ├── run-dag │ │ │ │ │ │ ├── run-dag.component.html │ │ │ │ │ │ ├── run-dag.component.scss │ │ │ │ │ │ ├── run-dag.component.spec.ts │ │ │ │ │ │ └── run-dag.component.ts │ │ │ │ │ ├── run-details │ │ │ │ │ │ ├── run-details.component.html │ │ │ │ │ │ ├── run-details.component.scss │ │ │ │ │ │ ├── run-details.component.spec.ts │ │ │ │ │ │ └── run-details.component.ts │ │ │ │ │ ├── run-events │ │ │ │ │ │ ├── run-events.component.html │ │ │ │ │ │ ├── run-events.component.scss │ │ │ │ │ │ ├── run-events.component.spec.ts │ │ │ │ │ │ └── run-events.component.ts │ │ │ │ │ ├── run-tests │ │ │ │ │ │ ├── run-tests.component.html │ │ │ │ │ │ ├── run-tests.component.scss │ │ │ │ │ │ ├── run-tests.component.spec.ts │ │ │ │ │ │ └── run-tests.component.ts │ │ │ │ │ ├── run-timeline │ │ │ │ │ │ ├── run-timeline.component.html │ │ │ │ │ │ ├── run-timeline.component.scss │ │ │ │ │ │ ├── run-timeline.component.spec.ts │ │ │ │ │ │ └── run-timeline.component.ts │ │ │ │ │ ├── runs-routing.module.ts │ │ │ │ │ ├── runs-table │ │ │ │ │ │ ├── run-states │ │ │ │ │ │ │ ├── run-states.component.html │ │ │ │ │ │ │ ├── run-states.component.scss │ │ │ │ │ │ │ ├── run-states.component.spec.ts │ │ │ │ │ │ │ └── run-states.component.ts │ │ │ │ │ │ ├── run-time │ │ │ │ │ │ │ ├── run-time.component.html │ │ │ │ │ │ │ ├── run-time.component.scss │ │ │ │ │ │ │ ├── run-time.component.spec.ts │ │ │ │ │ │ │ └── run-time.component.ts │ │ │ │ │ │ ├── runs-table.component.html │ │ │ │ │ │ ├── runs-table.component.scss │ │ │ │ │ │ ├── runs-table.component.spec.ts │ │ │ │ │ │ └── runs-table.component.ts │ │ │ │ │ ├── runs.module.ts │ │ │ │ │ └── runs.translation.ts │ │ │ │ ├── settings │ │ │ │ │ ├── settings.component.html │ │ │ │ │ ├── settings.component.scss │ │ │ │ │ ├── settings.component.spec.ts │ │ │ │ │ └── settings.component.ts │ │ │ │ ├── task-test-summary │ │ │ │ │ ├── task-test-summary.component.html │ │ │ │ │ ├── task-test-summary.component.scss │ │ │ │ │ ├── task-test-summary.component.spec.ts │ │ │ │ │ ├── task-test-summary.component.ts │ │ │ │ │ ├── task-test-summary.utils.spec.ts │ │ │ │ │ └── task-test-summary.utils.ts │ │ │ │ └── testgen-integration │ │ │ │ │ ├── testgen-integration.component.html │ │ │ │ │ ├── testgen-integration.component.scss │ │ │ │ │ ├── testgen-integration.component.spec.ts │ │ │ │ │ ├── testgen-integration.component.ts │ │ │ │ │ └── testgen-integration.model.ts │ │ │ ├── services │ │ │ │ ├── components │ │ │ │ │ ├── component.abstract.service.spec.ts │ │ │ │ │ ├── component.abstract.service.ts │ │ │ │ │ ├── components.service.spec.ts │ │ │ │ │ └── components.service.ts │ │ │ │ ├── instances │ │ │ │ │ ├── instances.service.spec.ts │ │ │ │ │ └── instances.service.ts │ │ │ │ ├── journeys │ │ │ │ │ ├── journeys.mock.ts │ │ │ │ │ ├── journeys.service.spec.ts │ │ │ │ │ └── journeys.service.ts │ │ │ │ ├── project-runs │ │ │ │ │ ├── project-runs.service.spec.ts │ │ │ │ │ └── project-runs.service.ts │ │ │ │ ├── run-events │ │ │ │ │ ├── run-events.mock.ts │ │ │ │ │ ├── run-events.service.spec.ts │ │ │ │ │ └── run-events.service.ts │ │ │ │ └── run-tasks │ │ │ │ │ ├── run-tasks.service.spec.ts │ │ │ │ │ └── run-tasks.service.ts │ │ │ └── stores │ │ │ │ ├── dag │ │ │ │ ├── dag.store.spec.ts │ │ │ │ └── dag.store.ts │ │ │ │ ├── instances │ │ │ │ ├── instances.store.spec.ts │ │ │ │ └── instances.store.ts │ │ │ │ ├── run-events │ │ │ │ ├── run-events.store.spec.ts │ │ │ │ └── run-events.store.ts │ │ │ │ ├── run-tasks │ │ │ │ ├── run-tasks.store.spec.ts │ │ │ │ └── run-tasks.store.ts │ │ │ │ └── runs │ │ │ │ ├── runs.store.spec.ts │ │ │ │ └── runs.store.ts │ │ ├── assets │ │ │ ├── .gitkeep │ │ │ ├── airflow.svg │ │ │ ├── apache_impala.svg │ │ │ ├── autosys.svg │ │ │ ├── aws_glue.svg │ │ │ ├── aws_lambda.svg │ │ │ ├── aws_s3.svg │ │ │ ├── aws_sagemaker.svg │ │ │ ├── azure_functions.svg │ │ │ ├── azure_ml.svg │ │ │ ├── azure_synapse_pipelines.svg │ │ │ ├── batch_pipeline.svg │ │ │ ├── blob_storage.svg │ │ │ ├── cloud_composer.svg │ │ │ ├── completed_with_warnings.svg │ │ │ ├── data_factory.svg │ │ │ ├── databricks.svg │ │ │ ├── dataops_automation.svg │ │ │ ├── dataops_testgen.svg │ │ │ ├── dataset.svg │ │ │ ├── dbt_core.svg │ │ │ ├── dk-logo.svg │ │ │ ├── fivetran.svg │ │ │ ├── goanywhere.svg │ │ │ ├── icons │ │ │ │ ├── icon-128x128.png │ │ │ │ ├── icon-144x144.png │ │ │ │ ├── icon-152x152.png │ │ │ │ ├── icon-192x192.png │ │ │ │ ├── icon-384x384.png │ │ │ │ ├── icon-512x512.png │ │ │ │ ├── icon-72x72.png │ │ │ │ └── icon-96x96.png │ │ │ ├── informatica.svg │ │ │ ├── loading.svg │ │ │ ├── logo.svg │ │ │ ├── module-federation.manifest.json │ │ │ ├── mssql.svg │ │ │ ├── neo4j.svg │ │ │ ├── oracle_database.svg │ │ │ ├── postgresql.svg │ │ │ ├── power_bi.svg │ │ │ ├── python.svg │ │ │ ├── qlik.svg │ │ │ ├── redshift.svg │ │ │ ├── server.svg │ │ │ ├── snowflake.svg │ │ │ ├── sqs.svg │ │ │ ├── streaming_pipeline.svg │ │ │ ├── tableau.svg │ │ │ └── talend.svg │ │ ├── bootstrap.ts │ │ ├── declarations.d.ts │ │ ├── environments │ │ │ ├── environment.json │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── manifest.webmanifest │ │ ├── module-federation.manifest.prod.json │ │ ├── polyfills.ts │ │ ├── styles.scss │ │ └── test-setup.ts │ │ ├── tsconfig.app.json │ │ ├── tsconfig.editor.json │ │ ├── tsconfig.json │ │ ├── tsconfig.spec.json │ │ ├── webpack.config.js │ │ ├── webpack.dev.config.js │ │ ├── webpack.prod.config.js │ │ └── webpack.staging.config.js ├── jest.config.ts ├── jest.preset.js ├── lerna.json ├── libs │ ├── .gitkeep │ ├── core │ │ ├── .eslintrc.json │ │ ├── README.md │ │ ├── jest.config.ts │ │ ├── package.json │ │ ├── project.json │ │ ├── src │ │ │ ├── index.ts │ │ │ ├── lib │ │ │ │ ├── actions │ │ │ │ │ ├── abstract-action │ │ │ │ │ │ ├── abstract-action.directive.spec.ts │ │ │ │ │ │ └── abstract-action.directive.ts │ │ │ │ │ ├── actions.model.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── config │ │ │ │ │ ├── app-configuration.ts │ │ │ │ │ ├── config.service.spec.ts │ │ │ │ │ ├── config.service.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── provide-from-config.ts │ │ │ │ ├── core.module.ts │ │ │ │ ├── decorators │ │ │ │ │ ├── host-resize │ │ │ │ │ │ ├── host-resize.ts │ │ │ │ │ │ └── host-resized.spec.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── entities │ │ │ │ │ ├── agent │ │ │ │ │ │ ├── agent.model.ts │ │ │ │ │ │ ├── service │ │ │ │ │ │ │ ├── agent.service.spec.ts │ │ │ │ │ │ │ └── agent.service.ts │ │ │ │ │ │ └── store │ │ │ │ │ │ │ ├── agent.actions.ts │ │ │ │ │ │ │ ├── agent.state.ts │ │ │ │ │ │ │ ├── agent.store.spec.ts │ │ │ │ │ │ │ └── agent.store.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── entity │ │ │ │ │ ├── entity-default-url.mappings.ts │ │ │ │ │ ├── entity-type.ts │ │ │ │ │ ├── entity.model.ts │ │ │ │ │ ├── entity.service.spec.ts │ │ │ │ │ ├── entity.service.ts │ │ │ │ │ ├── entity.store.spec.ts │ │ │ │ │ ├── entity.store.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── mock │ │ │ │ │ │ ├── mock.decorator.spec.ts │ │ │ │ │ │ └── mock.decorator.ts │ │ │ │ │ ├── read-only-rest-api.service.spec.ts │ │ │ │ │ └── read-only-rest-api.service.ts │ │ │ │ ├── guards │ │ │ │ │ ├── auth.guard.spec.ts │ │ │ │ │ ├── auth.guard.ts │ │ │ │ │ ├── no-auth │ │ │ │ │ │ ├── no-auth.guard.spec.ts │ │ │ │ │ │ └── no-auth.guard.ts │ │ │ │ │ ├── reset-stores.guard.spec.ts │ │ │ │ │ └── reset-stores.guard.ts │ │ │ │ ├── interceptors │ │ │ │ │ ├── base-http.interceptor.spec.ts │ │ │ │ │ ├── base-http.interceptor.ts │ │ │ │ │ ├── filter-params.interceptor.spec.ts │ │ │ │ │ ├── filter-params.interceptor.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── models │ │ │ │ │ ├── alert.model.ts │ │ │ │ │ ├── component.model.ts │ │ │ │ │ ├── event.model.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── instance.model.ts │ │ │ │ │ ├── integrations.model.ts │ │ │ │ │ ├── journey.model.ts │ │ │ │ │ └── runs.model.ts │ │ │ │ ├── resolvers │ │ │ │ │ └── entities │ │ │ │ │ │ ├── entities.resolver.spec.ts │ │ │ │ │ │ └── entities.resolver.ts │ │ │ │ ├── services │ │ │ │ │ ├── auth │ │ │ │ │ │ ├── auth.model.ts │ │ │ │ │ │ ├── session.service.spec.ts │ │ │ │ │ │ └── session.service.ts │ │ │ │ │ ├── company │ │ │ │ │ │ ├── company.model.ts │ │ │ │ │ │ ├── company.service.spec.ts │ │ │ │ │ │ └── company.service.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── organization │ │ │ │ │ │ ├── organization.model.ts │ │ │ │ │ │ ├── organization.service.spec.ts │ │ │ │ │ │ └── organization.service.ts │ │ │ │ │ ├── project │ │ │ │ │ │ ├── project.model.ts │ │ │ │ │ │ ├── project.service.spec.ts │ │ │ │ │ │ ├── project.service.ts │ │ │ │ │ │ ├── project.store.spec.ts │ │ │ │ │ │ └── project.store.ts │ │ │ │ │ └── user │ │ │ │ │ │ ├── user.model.ts │ │ │ │ │ │ ├── user.service.spec.ts │ │ │ │ │ │ └── user.service.ts │ │ │ │ ├── templating │ │ │ │ │ ├── abstract-templating.directive.ts │ │ │ │ │ └── index.ts │ │ │ │ └── utilities │ │ │ │ │ ├── batch-runs.utilities.spec.ts │ │ │ │ │ ├── batch-runs.utilities.ts │ │ │ │ │ ├── general.utilities.spec.ts │ │ │ │ │ ├── general.utilities.ts │ │ │ │ │ ├── instance.utilities.spec.ts │ │ │ │ │ ├── instance.utilities.ts │ │ │ │ │ ├── observable.utilities.spec.ts │ │ │ │ │ ├── observable.utilities.ts │ │ │ │ │ ├── tools.utilities.spec.ts │ │ │ │ │ ├── tools.utilities.ts │ │ │ │ │ ├── validators.spec.ts │ │ │ │ │ └── validators.ts │ │ │ └── test-setup.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.lib.json │ │ └── tsconfig.spec.json │ ├── translate │ │ ├── .eslintrc.json │ │ ├── README.md │ │ ├── jest.config.ts │ │ ├── package.json │ │ ├── project.json │ │ ├── src │ │ │ ├── index.ts │ │ │ ├── lib │ │ │ │ ├── translate.pipe.mock.ts │ │ │ │ ├── translate.pipe.spec.ts │ │ │ │ ├── translate.pipe.ts │ │ │ │ ├── translation.module.ts │ │ │ │ ├── translation.service.spec.ts │ │ │ │ └── translation.service.ts │ │ │ └── test-setup.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.lib.json │ │ └── tsconfig.spec.json │ ├── ui │ │ ├── .eslintrc.json │ │ ├── README.md │ │ ├── jest.config.ts │ │ ├── package.json │ │ ├── project.json │ │ ├── src │ │ │ ├── index.ts │ │ │ ├── lib │ │ │ │ ├── alert │ │ │ │ │ ├── alert.component.scss │ │ │ │ │ ├── alert.component.spec.ts │ │ │ │ │ └── alert.component.ts │ │ │ │ ├── breadcrumb │ │ │ │ │ ├── breadcrumb.component.html │ │ │ │ │ ├── breadcrumb.component.scss │ │ │ │ │ ├── breadcrumb.component.spec.ts │ │ │ │ │ ├── breadcrumb.component.ts │ │ │ │ │ ├── breadcrumb.model.ts │ │ │ │ │ └── breadcrumb.module.ts │ │ │ │ ├── code-snippet │ │ │ │ │ ├── code-snippet.component.html │ │ │ │ │ ├── code-snippet.component.scss │ │ │ │ │ ├── code-snippet.component.spec.ts │ │ │ │ │ └── code-snippet.component.ts │ │ │ │ ├── confirm-dialog │ │ │ │ │ ├── confirm-dialog.component.scss │ │ │ │ │ ├── confirm-dialog.component.spec.ts │ │ │ │ │ └── confirm-dialog.component.ts │ │ │ │ ├── created-by │ │ │ │ │ ├── created-by.component.spec.ts │ │ │ │ │ └── created-by.component.ts │ │ │ │ ├── dag │ │ │ │ │ ├── dag-actions │ │ │ │ │ │ ├── dag-actions.component.html │ │ │ │ │ │ ├── dag-actions.component.scss │ │ │ │ │ │ ├── dag-actions.component.spec.ts │ │ │ │ │ │ └── dag-actions.component.ts │ │ │ │ │ ├── dag-edge.directive.spec.ts │ │ │ │ │ ├── dag-edge.directive.ts │ │ │ │ │ ├── dag-legend.directive.spec.ts │ │ │ │ │ ├── dag-legend.directive.ts │ │ │ │ │ ├── dag-node.directive.spec.ts │ │ │ │ │ ├── dag-node.directive.ts │ │ │ │ │ ├── dag.component.html │ │ │ │ │ ├── dag.component.scss │ │ │ │ │ ├── dag.component.spec.ts │ │ │ │ │ ├── dag.component.ts │ │ │ │ │ ├── dag.model.ts │ │ │ │ │ ├── dag.module.ts │ │ │ │ │ ├── dag.translation.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── details-header │ │ │ │ │ ├── details-header.component.html │ │ │ │ │ ├── details-header.component.scss │ │ │ │ │ ├── details-header.component.spec.ts │ │ │ │ │ ├── details-header.component.ts │ │ │ │ │ ├── details-header.module.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── directives │ │ │ │ │ ├── bind-query-params │ │ │ │ │ │ ├── bind-query-params.abstract.spec.ts │ │ │ │ │ │ ├── bind-query-params.abstract.ts │ │ │ │ │ │ ├── bind-query-params.module.ts │ │ │ │ │ │ ├── to-mat-paginator │ │ │ │ │ │ │ ├── bind-query-params-mat-paginator.directive.spec.ts │ │ │ │ │ │ │ └── bind-query-params-mat-paginator.directive.ts │ │ │ │ │ │ ├── to-mat-sort │ │ │ │ │ │ │ ├── bind-query-params-mat-sort.directive.spec.ts │ │ │ │ │ │ │ └── bind-query-params-mat-sort.directive.ts │ │ │ │ │ │ └── to-mat-tab │ │ │ │ │ │ │ ├── bind-query-params-mat-tab.directive.spec.ts │ │ │ │ │ │ │ └── bind-query-params-mat-tab.directive.ts │ │ │ │ │ ├── click-confirm │ │ │ │ │ │ ├── click-confirm.directive.spec.ts │ │ │ │ │ │ └── click-confirm.directive.ts │ │ │ │ │ ├── dynamic-component │ │ │ │ │ │ ├── dynamic-component-outlet.directive.spec.ts │ │ │ │ │ │ ├── dynamic-component-outlet.directive.ts │ │ │ │ │ │ ├── dynamic-component.module.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── dk-tooltip │ │ │ │ │ ├── click-listener.service.spec.ts │ │ │ │ │ ├── click-listener.service.ts │ │ │ │ │ ├── dk-tooltip.component.html │ │ │ │ │ ├── dk-tooltip.component.scss │ │ │ │ │ ├── dk-tooltip.component.spec.ts │ │ │ │ │ ├── dk-tooltip.component.ts │ │ │ │ │ ├── dk-tooltip.directive.spec.ts │ │ │ │ │ ├── dk-tooltip.directive.ts │ │ │ │ │ ├── dk-tooltip.model.ts │ │ │ │ │ ├── dk-tooltip.module.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── dots-chart │ │ │ │ │ ├── dot-template.directive.ts │ │ │ │ │ ├── dot.component.scss │ │ │ │ │ ├── dot.component.spec.ts │ │ │ │ │ ├── dot.component.ts │ │ │ │ │ ├── dots-chart.component.html │ │ │ │ │ ├── dots-chart.component.scss │ │ │ │ │ ├── dots-chart.component.spec.ts │ │ │ │ │ ├── dots-chart.component.ts │ │ │ │ │ └── drill-in.directive.ts │ │ │ │ ├── duration │ │ │ │ │ ├── duration.component.spec.ts │ │ │ │ │ ├── duration.component.ts │ │ │ │ │ ├── duration.module.ts │ │ │ │ │ ├── duration.pipe.spec.ts │ │ │ │ │ ├── duration.pipe.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── element-ref │ │ │ │ │ ├── element-ref.directive.spec.ts │ │ │ │ │ └── element-ref.directive.ts │ │ │ │ ├── empty-state-setup │ │ │ │ │ ├── empty-state-setup.component.html │ │ │ │ │ ├── empty-state-setup.component.scss │ │ │ │ │ ├── empty-state-setup.component.spec.ts │ │ │ │ │ └── empty-state-setup.component.ts │ │ │ │ ├── entity │ │ │ │ │ ├── active-status-chip │ │ │ │ │ │ ├── active-status-chip.component.html │ │ │ │ │ │ ├── active-status-chip.component.spec.ts │ │ │ │ │ │ └── active-status-chip.component.ts │ │ │ │ │ ├── entity-list-placeholder │ │ │ │ │ │ ├── entity-list-placeholder.component.html │ │ │ │ │ │ ├── entity-list-placeholder.component.scss │ │ │ │ │ │ ├── entity-list-placeholder.component.spec.ts │ │ │ │ │ │ └── entity-list-placeholder.component.ts │ │ │ │ │ ├── entity.module.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── nullify-pending │ │ │ │ │ │ ├── nullify-pending.pipe.spec.ts │ │ │ │ │ │ └── nullify-pending.pipe.ts │ │ │ │ ├── expansion-panel │ │ │ │ │ ├── expansion-panel-content │ │ │ │ │ │ ├── expansion-panel-content.component.spec.ts │ │ │ │ │ │ └── expansion-panel-content.component.ts │ │ │ │ │ ├── expansion-panel-title │ │ │ │ │ │ ├── expansion-panel-title.component.spec.ts │ │ │ │ │ │ └── expansion-panel-title.component.ts │ │ │ │ │ ├── expansion-panel.module.ts │ │ │ │ │ ├── expansion-panel │ │ │ │ │ │ ├── expansion-panel.component.html │ │ │ │ │ │ ├── expansion-panel.component.scss │ │ │ │ │ │ ├── expansion-panel.component.spec.ts │ │ │ │ │ │ └── expansion-panel.component.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── fields │ │ │ │ │ ├── abstract-field.spec.ts │ │ │ │ │ ├── abstract-field.ts │ │ │ │ │ ├── abstract-mat-form-field-control.directive.spec.ts │ │ │ │ │ ├── abstract-mat-form-field-control.directive.ts │ │ │ │ │ ├── checkbox-field │ │ │ │ │ │ ├── checkbox-field.component.html │ │ │ │ │ │ ├── checkbox-field.component.scss │ │ │ │ │ │ ├── checkbox-field.component.spec.ts │ │ │ │ │ │ ├── checkbox-field.component.ts │ │ │ │ │ │ └── checkbox-field.module.ts │ │ │ │ │ ├── filter-field │ │ │ │ │ │ ├── filter-field-option.component.ts │ │ │ │ │ │ ├── filter-field.component.html │ │ │ │ │ │ ├── filter-field.component.scss │ │ │ │ │ │ ├── filter-field.component.spec.ts │ │ │ │ │ │ ├── filter-field.component.ts │ │ │ │ │ │ └── filter-field.module.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── schedule-field │ │ │ │ │ │ ├── schedule-field.component.html │ │ │ │ │ │ ├── schedule-field.component.scss │ │ │ │ │ │ ├── schedule-field.component.spec.ts │ │ │ │ │ │ ├── schedule-field.component.ts │ │ │ │ │ │ ├── schedule-field.model.ts │ │ │ │ │ │ ├── schedule-field.module.ts │ │ │ │ │ │ ├── schedule.pipe.spec.ts │ │ │ │ │ │ └── schedule.pipe.ts │ │ │ │ │ ├── text-field │ │ │ │ │ │ ├── text-field-error.component.spec.ts │ │ │ │ │ │ ├── text-field-error.component.ts │ │ │ │ │ │ ├── text-field.component.html │ │ │ │ │ │ ├── text-field.component.scss │ │ │ │ │ │ ├── text-field.component.spec.ts │ │ │ │ │ │ ├── text-field.component.ts │ │ │ │ │ │ └── text-field.module.ts │ │ │ │ │ └── timespan-field │ │ │ │ │ │ ├── timespan-field.component.html │ │ │ │ │ │ ├── timespan-field.component.scss │ │ │ │ │ │ ├── timespan-field.component.spec.ts │ │ │ │ │ │ ├── timespan-field.component.ts │ │ │ │ │ │ ├── timespan-field.module.ts │ │ │ │ │ │ ├── timespan.pipe.spec.ts │ │ │ │ │ │ ├── timespan.pipe.ts │ │ │ │ │ │ └── timespan.translation.ts │ │ │ │ ├── gantt-chart │ │ │ │ │ ├── gantt-bar.directive.spec.ts │ │ │ │ │ ├── gantt-bar.directive.ts │ │ │ │ │ ├── gantt-chart.component.html │ │ │ │ │ ├── gantt-chart.component.scss │ │ │ │ │ ├── gantt-chart.component.spec.ts │ │ │ │ │ ├── gantt-chart.component.ts │ │ │ │ │ ├── gantt-chart.model.ts │ │ │ │ │ ├── gantt-chart.module.ts │ │ │ │ │ ├── gantt-label.directive.ts │ │ │ │ │ ├── gantt-task.component.spec.ts │ │ │ │ │ └── gantt-task.component.ts │ │ │ │ ├── help-link │ │ │ │ │ ├── help-link.component.spec.ts │ │ │ │ │ └── help-link.component.ts │ │ │ │ ├── is-today │ │ │ │ │ ├── is-today.pipe.spec.ts │ │ │ │ │ └── is-today.pipe.ts │ │ │ │ ├── labeled-menu │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── labeled-menu.component.html │ │ │ │ │ ├── labeled-menu.component.scss │ │ │ │ │ ├── labeled-menu.component.spec.ts │ │ │ │ │ ├── labeled-menu.component.ts │ │ │ │ │ └── labeled-menu.module.ts │ │ │ │ ├── mat-card-edit │ │ │ │ │ ├── mat-card-edit.component.html │ │ │ │ │ ├── mat-card-edit.component.scss │ │ │ │ │ ├── mat-card-edit.component.spec.ts │ │ │ │ │ └── mat-card-edit.component.ts │ │ │ │ ├── metadata-viewer │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── metadata-viewer.component.html │ │ │ │ │ ├── metadata-viewer.component.scss │ │ │ │ │ ├── metadata-viewer.component.spec.ts │ │ │ │ │ ├── metadata-viewer.component.ts │ │ │ │ │ └── metadata-viewer.module.ts │ │ │ │ ├── pipes │ │ │ │ │ ├── get-integration │ │ │ │ │ │ ├── get-integration.pipe.spec.ts │ │ │ │ │ │ └── get-integration.pipe.ts │ │ │ │ │ ├── humanize │ │ │ │ │ │ ├── humanize.pipe.spec.ts │ │ │ │ │ │ └── humanize.pipe.ts │ │ │ │ │ ├── parseDate │ │ │ │ │ │ ├── parseDate.pipe.spec.ts │ │ │ │ │ │ └── parseDate.pipe.ts │ │ │ │ │ └── sum │ │ │ │ │ │ ├── sum.pipe.spec.ts │ │ │ │ │ │ └── sum.pipe.ts │ │ │ │ ├── selected-actions │ │ │ │ │ ├── selected-actions.component.html │ │ │ │ │ ├── selected-actions.component.scss │ │ │ │ │ ├── selected-actions.component.spec.ts │ │ │ │ │ └── selected-actions.component.ts │ │ │ │ ├── table-wrapper │ │ │ │ │ ├── drag-disabled.directive.spec.ts │ │ │ │ │ ├── drag-disabled.directive.ts │ │ │ │ │ ├── header-label.directive.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── sort-disabled.directive.spec.ts │ │ │ │ │ ├── sort-disabled.directive.ts │ │ │ │ │ ├── table-wrapper-actions.component.spec.ts │ │ │ │ │ ├── table-wrapper-actions.component.ts │ │ │ │ │ ├── table-wrapper.component.html │ │ │ │ │ ├── table-wrapper.component.scss │ │ │ │ │ ├── table-wrapper.component.spec.ts │ │ │ │ │ ├── table-wrapper.component.ts │ │ │ │ │ ├── table-wrapper.model.ts │ │ │ │ │ ├── table-wrapper.module.ts │ │ │ │ │ ├── table-wrapper.translation.ts │ │ │ │ │ ├── toggle-disabled.directive.spec.ts │ │ │ │ │ └── toggle-disabled.directive.ts │ │ │ │ ├── truncate │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── truncate.directive.spec.ts │ │ │ │ │ ├── truncate.directive.ts │ │ │ │ │ └── truncate.module.ts │ │ │ │ └── ui.module.ts │ │ │ └── test-setup.ts │ │ ├── styles │ │ │ ├── _details-page.scss │ │ │ ├── _dialog.scss │ │ │ ├── _fields.scss │ │ │ ├── _fx-flex.scss │ │ │ ├── _gantt-chart.scss │ │ │ ├── _icon-size.scss │ │ │ ├── _list-page.scss │ │ │ ├── _mixins.scss │ │ │ ├── _overlay.scss │ │ │ ├── _rules.scss │ │ │ ├── _spacing.scss │ │ │ ├── _theme.scss │ │ │ ├── _variables.scss │ │ │ └── material │ │ │ │ └── colors.scss │ │ ├── tsconfig.json │ │ ├── tsconfig.lib.json │ │ └── tsconfig.spec.json │ └── webpack-config │ │ ├── index.js │ │ ├── libs.js │ │ ├── mapped-paths.js │ │ └── package.json ├── migrations.json ├── nginx.conf ├── nx.json ├── package.json ├── tools │ ├── executors │ │ └── version │ │ │ ├── executor.json │ │ │ ├── impl.js │ │ │ ├── impl.ts │ │ │ ├── package.json │ │ │ └── schema.json │ └── tsconfig.tools.json ├── tsconfig.base.json └── yarn.lock ├── pyproject.toml ├── rules_engine ├── __init__.py ├── __main__.py ├── engine.py ├── journey_rules.py ├── lib.py ├── project_rules.py ├── rule_data.py ├── tests │ ├── __init__.py │ ├── integration │ │ ├── __init__.py │ │ ├── conftest.py │ │ ├── test_rule_data.py │ │ ├── test_rules.py │ │ └── test_rules_engine.py │ └── unit │ │ ├── __init__.py │ │ ├── actions │ │ └── __init__.py │ │ ├── conftest.py │ │ ├── test_data_points.py │ │ └── test_engine.py └── typing.py ├── run_manager ├── __init__.py ├── __main__.py ├── alerts.py ├── context.py ├── event_handlers │ ├── __init__.py │ ├── component_identifier.py │ ├── dataset_handler.py │ ├── incomplete_instance_handler.py │ ├── instance_handler.py │ ├── out_of_sequence_instance_handler.py │ ├── run_handler.py │ ├── run_unexpected_status_change_handler.py │ ├── schedule_handlers.py │ ├── scheduled_instance_handler.py │ ├── task_handler.py │ ├── test_outcome_handler.py │ └── utils.py ├── run_manager.py └── tests │ ├── __init__.py │ ├── integration │ ├── __init__.py │ ├── conftest.py │ ├── event_handlers │ │ ├── __init__.py │ │ ├── test_component_identifier.py │ │ ├── test_incomplete_instance_handler.py │ │ └── test_out_of_sequence_instance_handler.py │ ├── test_alerts.py │ ├── test_dataset_handler.py │ ├── test_instance_handler.py │ ├── test_run_handler.py │ ├── test_run_identifier.py │ ├── test_run_manager.py │ ├── test_run_manager_instance.py │ ├── test_run_manager_payload_instance.py │ ├── test_run_manager_tasks.py │ ├── test_run_manager_test_outcomes.py │ ├── test_run_manager_unordered_events.py │ ├── test_scheduled_instance_handler.py │ ├── test_scheduler_events.py │ ├── test_task_handler.py │ └── test_test_outcome_handler.py │ └── unit │ ├── __init__.py │ ├── conftest.py │ ├── test_run_manager.py │ └── test_schedule_handlers.py ├── scheduler ├── __init__.py ├── __main__.py ├── agent_check.py ├── component_expectations.py ├── instance_expectations.py ├── schedule_source.py └── tests │ ├── __init__.py │ ├── integration │ ├── __init__.py │ ├── conftest.py │ ├── test_agent_scheduler.py │ └── test_schedule_source.py │ └── unit │ ├── __init__.py │ ├── conftest.py │ ├── test_agent_scheduler.py │ ├── test_component_scheduler.py │ ├── test_instance_scheduler.py │ └── test_schedule_source.py ├── scripts ├── __init__.py ├── check-docker-extensions.py ├── check-tests-are-marked.py └── invocations │ ├── __init__.py │ ├── common.py │ ├── deploy.py │ ├── dev.py │ └── test.py ├── setup.cfg ├── subcommand ├── README.md ├── __init__.py ├── subcmd.py └── tests │ ├── __init__.py │ └── test_subcommand.py ├── tasks.py └── testlib ├── __init__.py ├── fixtures ├── __init__.py ├── entities.py ├── internal_events.py ├── v1_events.py ├── v2_events.py └── web_server.py └── peewee.py /.dockerignore: -------------------------------------------------------------------------------- 1 | **/__pycache__/ 2 | **/tests/ 3 | *.egg-info/ 4 | *.md 5 | */collaborate_swagger_spec.yaml 6 | */observability_swagger_spec.yaml 7 | .git* 8 | .idea/ 9 | .mypy_cache/ 10 | .pytest_cache/ 11 | .venv/ 12 | build/ 13 | dist/ 14 | instance/ 15 | **/node_modules/ 16 | node_modules/ 17 | scripts/ 18 | venv/ 19 | **/.angular/ 20 | .angular/ 21 | .env* 22 | .assets/ 23 | .serverless/ 24 | tmp/ 25 | reports/ 26 | .prettierignore 27 | prettierrc 28 | !.env.project 29 | !.env.vault 30 | serverless.yml 31 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Release New Version 2 | on: 3 | push: 4 | branches: 5 | - main 6 | workflow_dispatch: 7 | branches: 8 | - main 9 | jobs: 10 | publish: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout Latest Changes 14 | uses: actions/checkout@v4 15 | with: 16 | fetch-depth: 0 17 | 18 | - name: Package and Publish Charts 19 | uses: ./.github/actions/publish_charts 20 | with: 21 | github-token: '${{ secrets.GITHUB_TOKEN }}' 22 | -------------------------------------------------------------------------------- /.redocly.lint-ignore.yaml: -------------------------------------------------------------------------------- 1 | # This file instructs Redocly's linter to ignore the rules contained for specific parts of your API. 2 | # See https://redoc.ly/docs/cli/ for more information. 3 | observability_swagger_spec.yaml: 4 | operation-4xx-response: 5 | - '#/paths/~1observability~1v1~1instances/get/responses' 6 | - '#/paths/~1observability~1v1~1upcoming-instances/get/responses' 7 | -------------------------------------------------------------------------------- /.redocly.yaml: -------------------------------------------------------------------------------- 1 | extends: 2 | - recommended 3 | 4 | apis: 5 | observability@v1: 6 | root: ./observability_swagger_spec.yaml 7 | rules: 8 | operation-summary: off 9 | no-unused-components: off 10 | event@v1: 11 | root: ./events_swagger_spec_v1.yaml 12 | event@v2: 13 | root: ./events_swagger_spec_v2.yaml 14 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | DataKitchen DataOps Observability 2 | Copyright 2024 DataKitchen, Inc. 3 | 4 | This product includes software developed at 5 | DataKitchen, Inc. (https://datakitchen.io/). 6 | -------------------------------------------------------------------------------- /agent_api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/agent_api/__init__.py -------------------------------------------------------------------------------- /agent_api/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/agent_api/config/__init__.py -------------------------------------------------------------------------------- /agent_api/config/cloud.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | # Flask specific settings: https://flask.palletsprojects.com/en/latest/config/#builtin-configuration-values 4 | SECRET_KEY: str = os.environ["AGENT_API_KEY_FLASK_SECRET"] 5 | SERVER_NAME: str = os.environ["AGENT_API_HOSTNAME"] 6 | -------------------------------------------------------------------------------- /agent_api/config/local.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | # Flask specific settings: https://flask.palletsprojects.com/en/latest/config/#builtin-configuration-values 4 | PROPAGATE_EXCEPTIONS: Optional[bool] = True 5 | SECRET_KEY: str = "NOT_VERY_SECRET" 6 | -------------------------------------------------------------------------------- /agent_api/config/minikube.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | # Flask specific settings: https://flask.palletsprojects.com/en/latest/config/#builtin-configuration-values 4 | TESTING: Optional[bool] = True 5 | SECRET_KEY: str = "NOT_VERY_SECRET" 6 | -------------------------------------------------------------------------------- /agent_api/config/test.py: -------------------------------------------------------------------------------- 1 | from peewee import SqliteDatabase 2 | 3 | DATABASE = { 4 | "name": "file:cachedb?mode=memory&cache=shared", 5 | "engine": SqliteDatabase, 6 | "pragmas": {}, 7 | } 8 | """Configures an in-memory database with a shared cache for testing.""" 9 | 10 | API_PREFIX: str = "agent" 11 | 12 | TESTING: bool = True 13 | """Enable flask TESTING mode. This is needed to get around the default-key security check.""" 14 | -------------------------------------------------------------------------------- /agent_api/endpoints/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/agent_api/endpoints/__init__.py -------------------------------------------------------------------------------- /agent_api/endpoints/v1/__init__.py: -------------------------------------------------------------------------------- 1 | from .heartbeat import * 2 | -------------------------------------------------------------------------------- /agent_api/helpers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/agent_api/helpers/__init__.py -------------------------------------------------------------------------------- /agent_api/helpers/health.py: -------------------------------------------------------------------------------- 1 | from common.entities import DB 2 | from common.kubernetes.readiness_probe import NotReadyException 3 | 4 | 5 | def readiness_probe() -> None: 6 | if DB.obj is None: 7 | raise NotReadyException("Database not initialized") 8 | -------------------------------------------------------------------------------- /agent_api/routes/__init__.py: -------------------------------------------------------------------------------- 1 | from .v1_routes import * 2 | -------------------------------------------------------------------------------- /agent_api/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | from .heartbeat import * 2 | -------------------------------------------------------------------------------- /agent_api/schemas/heartbeat.py: -------------------------------------------------------------------------------- 1 | __all__ = ("HeartbeatSchema",) 2 | 3 | from marshmallow import Schema 4 | from marshmallow.fields import AwareDateTime, String 5 | from marshmallow.validate import Length 6 | 7 | 8 | class HeartbeatSchema(Schema): 9 | key = String(required=True, validate=Length(max=255)) 10 | tool = String(required=True, validate=Length(max=255)) 11 | version = String(required=True, validate=Length(max=255)) 12 | latest_event_timestamp = AwareDateTime(format="iso", load_default=None, dump_default=None) 13 | -------------------------------------------------------------------------------- /agent_api/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/agent_api/tests/__init__.py -------------------------------------------------------------------------------- /agent_api/tests/integration/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/agent_api/tests/integration/__init__.py -------------------------------------------------------------------------------- /agent_api/tests/integration/v1_endpoints/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/agent_api/tests/integration/v1_endpoints/__init__.py -------------------------------------------------------------------------------- /benchmark/README.md: -------------------------------------------------------------------------------- 1 | # Benchmarks 2 | 3 | Scripts in this folder are intended to be used to validate performance of implementations. 4 | 5 | ## Cached Property 6 | The ``cached_property.py`` benchmark compares the ``common.decorators`` implementation of ``cached_property`` with 7 | the standard library implementation as well as the one included with ``boltons``. 8 | 9 | To run the benchmark from the ``observability`` project root, first make sure you've activated your virtual environment, 10 | then follow these steps. 11 | 12 | Install benchmarking requirements: 13 | ```bash 14 | $ python -m pip install -r benchmark/requirements.txt 15 | ``` 16 | 17 | Run the benchmark 18 | ```bash 19 | $ python benchmark/cached_property.py 20 | ``` 21 | -------------------------------------------------------------------------------- /benchmark/requirements.txt: -------------------------------------------------------------------------------- 1 | boltons>=23.0 2 | pyperf>=2.6 3 | -------------------------------------------------------------------------------- /cli/entry_points/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/cli/entry_points/__init__.py -------------------------------------------------------------------------------- /cli/graph_templates/head.html: -------------------------------------------------------------------------------- 1 | digraph name { 2 | fontname = "Helvetica" 3 | fontsize = 8 4 | node [ 5 | fontname = "Helvetica" 6 | fontsize = 8 7 | shape = "plaintext" 8 | ] 9 | edge [ 10 | fontname = "Helvetica" 11 | fontsize = 8 12 | ] 13 | overlap=false 14 | -------------------------------------------------------------------------------- /cli/graph_templates/rel.html: -------------------------------------------------------------------------------- 1 | {% for model in models %}{% for relation in model.relations %}{% if relation.needs_node %}{{ relation.target_app }}_{{ relation.target }} [label=< 2 | 3 | 5 |
4 | {{ relation.target }}
6 | >] 7 | {% endif %} 8 | {{ model.app_name }}_{{ model.name }} -> {{ relation.target_app }}_{{ relation.target }} 9 | [label="{{ relation.label }}"] {{ relation.arrows }}; 10 | {% endfor %}{% endfor %} 11 | -------------------------------------------------------------------------------- /cli/graph_templates/tail.html: -------------------------------------------------------------------------------- 1 | } 2 | -------------------------------------------------------------------------------- /cli/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/cli/tests/__init__.py -------------------------------------------------------------------------------- /cli/tests/entry_points/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/cli/tests/entry_points/__init__.py -------------------------------------------------------------------------------- /cli/tests/entry_points/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from peewee import SqliteDatabase 3 | 4 | from common.entities import DB 5 | 6 | 7 | @pytest.fixture 8 | def test_db(): 9 | DB.initialize(SqliteDatabase(":memory:", pragmas={"foreign_keys": 1})) 10 | yield DB 11 | DB.obj = None 12 | -------------------------------------------------------------------------------- /cli/tests/test_imports.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from cli import modules 4 | 5 | 6 | @pytest.mark.unit 7 | @pytest.mark.parametrize("module", modules) 8 | def test_entry_point_import(module): 9 | """Validates that all specified entry points can be imported without errors.""" 10 | try: 11 | __import__(module) 12 | except ImportError as e: 13 | raise AssertionError(f"Unable to import entry point: {module}") from e 14 | except Exception as e: 15 | raise AssertionError(f"Unexpected error importing entry point: {module}") from e 16 | -------------------------------------------------------------------------------- /common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/__init__.py -------------------------------------------------------------------------------- /common/actions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/actions/__init__.py -------------------------------------------------------------------------------- /common/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/api/__init__.py -------------------------------------------------------------------------------- /common/api/flask_ext/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/api/flask_ext/__init__.py -------------------------------------------------------------------------------- /common/api/flask_ext/authentication/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ["ServiceAccountAuth", "JWTAuth"] 2 | 3 | from .jwt_plugin import JWTAuth 4 | from .service_account_key_plugin import ServiceAccountAuth 5 | -------------------------------------------------------------------------------- /common/auth/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/auth/__init__.py -------------------------------------------------------------------------------- /common/auth/keys/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/auth/keys/__init__.py -------------------------------------------------------------------------------- /common/auth/keys/settings.py: -------------------------------------------------------------------------------- 1 | HASH_ITERATIONS: int = 390_000 2 | """ 3 | Default iterations for hashing a supplied password. 4 | 5 | This number is picked somewhat at random. It needs to be significantly large to yield an appropriate work factor 6 | but the exact value doesn't matter. 7 | """ 8 | 9 | DEFAULT_EXPIRY_DAYS: int = 365 10 | """Default length of time an API key is valid; defaults to 1 year (365 days).""" 11 | -------------------------------------------------------------------------------- /common/constants/__init__.py: -------------------------------------------------------------------------------- 1 | from .defaults import * 2 | from .email_templates import * 3 | from .peewee import * 4 | from .rbac import * 5 | from .schema_limits import * 6 | from .schema_validation import * 7 | from .validation_messages import * 8 | -------------------------------------------------------------------------------- /common/constants/defaults.py: -------------------------------------------------------------------------------- 1 | import zoneinfo 2 | 3 | SCHEDULE_START_CRON_TIMEZONE: zoneinfo.ZoneInfo = zoneinfo.ZoneInfo("UTC") 4 | -------------------------------------------------------------------------------- /common/constants/peewee.py: -------------------------------------------------------------------------------- 1 | BATCH_SIZE: int = 100 2 | """Default batch size for large updates.""" 3 | -------------------------------------------------------------------------------- /common/constants/rbac.py: -------------------------------------------------------------------------------- 1 | ADMIN_ROLE = "ADMIN" 2 | """The name given to the administrative role.""" 3 | -------------------------------------------------------------------------------- /common/constants/schema_validation.py: -------------------------------------------------------------------------------- 1 | EXTENDED_ALPHANUMERIC_REGEX = r"^(?!_)[\w ]*(? Optional[ForeignKeyField]: 17 | return None 18 | -------------------------------------------------------------------------------- /common/entities/dataset.py: -------------------------------------------------------------------------------- 1 | __all__ = ["Dataset"] 2 | 3 | 4 | from .base_entity import BaseModel 5 | from .component import ComponentType 6 | from .component_meta import SimpleComponentMeta 7 | 8 | 9 | class Dataset(BaseModel, metaclass=SimpleComponentMeta): 10 | """Representation of a dataset component in the application.""" 11 | 12 | component_type = ComponentType.DATASET.name 13 | -------------------------------------------------------------------------------- /common/entities/organization.py: -------------------------------------------------------------------------------- 1 | __all__ = ["Organization"] 2 | 3 | from peewee import CharField, ForeignKeyField 4 | 5 | from .base_entity import AuditEntityMixin, BaseEntity 6 | from .company import Company 7 | 8 | 9 | class Organization(BaseEntity, AuditEntityMixin): 10 | """Second tier of hierarchy -- representing a subsection of the Company""" 11 | 12 | name = CharField(null=False) 13 | description = CharField(null=True) 14 | company = ForeignKeyField(Company, backref="organizations", on_delete="CASCADE", null=False, index=True) 15 | 16 | class Meta: 17 | # Multi-column indexes 18 | indexes = ( 19 | # Unique index across company + name 20 | (("company", "name"), True), 21 | ) 22 | -------------------------------------------------------------------------------- /common/entities/pipeline.py: -------------------------------------------------------------------------------- 1 | __all__ = ["Pipeline"] 2 | 3 | 4 | from .base_entity import BaseModel 5 | from .component import ComponentType 6 | from .component_meta import SimpleComponentMeta 7 | 8 | 9 | class Pipeline(BaseModel, metaclass=SimpleComponentMeta): 10 | """Representation of a batch-pipeline component in the application.""" 11 | 12 | component_type = ComponentType.BATCH_PIPELINE.name 13 | -------------------------------------------------------------------------------- /common/entities/server.py: -------------------------------------------------------------------------------- 1 | __all__ = ["Server"] 2 | 3 | 4 | from .base_entity import BaseModel 5 | from .component import ComponentType 6 | from .component_meta import SimpleComponentMeta 7 | 8 | 9 | class Server(BaseModel, metaclass=SimpleComponentMeta): 10 | """Representation of a server component in the application.""" 11 | 12 | component_type = ComponentType.SERVER.name 13 | -------------------------------------------------------------------------------- /common/entities/streaming_pipeline.py: -------------------------------------------------------------------------------- 1 | __all__ = ["StreamingPipeline"] 2 | 3 | 4 | from .base_entity import BaseModel 5 | from .component import ComponentType 6 | from .component_meta import SimpleComponentMeta 7 | 8 | 9 | class StreamingPipeline(BaseModel, metaclass=SimpleComponentMeta): 10 | """Representation of a streaming-pipeline component in the application.""" 11 | 12 | component_type = ComponentType.STREAMING_PIPELINE.name 13 | -------------------------------------------------------------------------------- /common/entities/upcoming_instance.py: -------------------------------------------------------------------------------- 1 | __all__ = ["UpcomingInstance"] 2 | from dataclasses import dataclass 3 | from datetime import datetime 4 | from typing import Optional 5 | 6 | from common.entities.journey import Journey 7 | 8 | 9 | @dataclass 10 | class UpcomingInstance: 11 | journey: Journey 12 | expected_start_time: Optional[datetime] = None 13 | expected_end_time: Optional[datetime] = None 14 | -------------------------------------------------------------------------------- /common/entity_services/__init__.py: -------------------------------------------------------------------------------- 1 | from .company_service import * 2 | from .component_service import * 3 | from .event_service import * 4 | from .instance_service import * 5 | from .journey_service import * 6 | from .organization_service import * 7 | from .pipeline_service import * 8 | from .project_service import * 9 | from .run_service import * 10 | from .sa_key_service import * 11 | from .test_outcome_service import * 12 | from .upcoming_instance_service import * 13 | from .user_service import * 14 | -------------------------------------------------------------------------------- /common/entity_services/agent_service.py: -------------------------------------------------------------------------------- 1 | __all__ = ["get_agents_with_rules"] 2 | 3 | from common.entities import Agent 4 | from common.entity_services.helpers import ListRules 5 | from common.entity_services.helpers.list_rules import Page 6 | 7 | 8 | def get_agents_with_rules(project_id: str, rules: ListRules) -> Page[Agent]: 9 | base_query = Agent.project == project_id 10 | if rules.search is not None: 11 | search_query = (Agent.key ** f"%{rules.search}%") | (Agent.tool ** f"%{rules.search}%") 12 | base_query &= search_query 13 | query = Agent.select().where(base_query) 14 | results = query.order_by(rules.order_by_field(Agent.key)).paginate(rules.page, rules.count) 15 | return Page[Agent](results=results, total=query.count()) 16 | -------------------------------------------------------------------------------- /common/entity_services/helpers/__init__.py: -------------------------------------------------------------------------------- 1 | from .filter_rules import * 2 | from .list_rules import * 3 | -------------------------------------------------------------------------------- /common/entity_services/organization_service.py: -------------------------------------------------------------------------------- 1 | __all__ = ["OrganizationService"] 2 | 3 | from common.entities import Project 4 | from common.entity_services.helpers import ListRules 5 | from common.entity_services.helpers.list_rules import Page 6 | 7 | 8 | class OrganizationService: 9 | @staticmethod 10 | def get_projects_with_rules(org_id: str, rules: ListRules) -> Page[Project]: 11 | query = Project.organization == org_id 12 | 13 | if rules.search is not None: 14 | query &= Project.name ** f"%{rules.search}%" 15 | 16 | results = Project.select().where(query) 17 | return Page[Project].get_paginated_results(results, Project.name, rules) 18 | -------------------------------------------------------------------------------- /common/entity_services/pipeline_service.py: -------------------------------------------------------------------------------- 1 | __all__ = ["PipelineService"] 2 | import logging 3 | from typing import Optional 4 | 5 | from common.entities import Pipeline 6 | 7 | LOG = logging.getLogger(__name__) 8 | 9 | 10 | class PipelineService: 11 | @staticmethod 12 | def get_by_key_and_project(pipeline_key: Optional[str], project_id: str) -> Pipeline: 13 | pipeline: Pipeline = Pipeline.get(Pipeline.key == pipeline_key, Pipeline.project == project_id) 14 | return pipeline 15 | -------------------------------------------------------------------------------- /common/entity_services/sa_key_service.py: -------------------------------------------------------------------------------- 1 | from common.entities import Project, ServiceAccountKey 2 | from common.entity_services.helpers import ListRules, Page 3 | 4 | 5 | class ServiceAccountKeyService: 6 | @staticmethod 7 | def list_with_rules(*, project: Project, rules: ListRules) -> Page[ServiceAccountKey]: 8 | query = ServiceAccountKey.project == project 9 | if rules.search is not None: 10 | query &= (ServiceAccountKey.name ** f"%{rules.search}%") | ( 11 | ServiceAccountKey.description ** f"%{rules.search}%" 12 | ) 13 | results = ServiceAccountKey.select().where(query) 14 | return Page[ServiceAccountKey].get_paginated_results(results, ServiceAccountKey.name, rules) 15 | -------------------------------------------------------------------------------- /common/entity_services/user_service.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from common.entities import User 4 | from common.entity_services.helpers import ListRules, Page 5 | 6 | 7 | class UserService: 8 | @staticmethod 9 | def list_with_rules( 10 | rules: ListRules, company_id: Optional[str] = None, name_filter: Optional[str] = None 11 | ) -> Page[User]: 12 | query = User.select() 13 | if company_id: 14 | query = query.where(User.primary_company_id == company_id) 15 | if name_filter: 16 | query = query.where(User.name.contains(name_filter)) 17 | return Page[User].get_paginated_results(query, User.name, rules) 18 | -------------------------------------------------------------------------------- /common/events/__init__.py: -------------------------------------------------------------------------------- 1 | from .converters import USER_EVENT_TYPES, to_v1, to_v2 # noqa: F401 2 | from .enums import * 3 | from .event_handler import * 4 | from .v1.event import Event # noqa: F401 5 | from .v2.base import EventV2 # noqa: F401 6 | -------------------------------------------------------------------------------- /common/events/enums.py: -------------------------------------------------------------------------------- 1 | __all__ = ["ScheduleType"] 2 | 3 | from enum import Enum 4 | 5 | 6 | class ScheduleType(Enum): 7 | BATCH_START_TIME = "BATCH_START_TIME" 8 | BATCH_START_TIME_MARGIN = "BATCH_START_TIME_MARGIN" 9 | BATCH_END_TIME = "BATCH_END_TIME" 10 | DATASET_ARRIVAL_MARGIN = "DATASET_ARRIVAL_MARGIN" 11 | 12 | 13 | class EventSources(Enum): 14 | API = "API" 15 | USER = "USER" 16 | SCHEDULER = "SCHEDULER" 17 | RULES_ENGINE = "RULES_ENGINE" 18 | # This last one should be considered a bug if seen in the wild. But it can be used as a dumb-default for tracing. 19 | UNKNOWN = "UNKNOWN" 20 | -------------------------------------------------------------------------------- /common/events/internal/__init__.py: -------------------------------------------------------------------------------- 1 | from .alert import * 2 | from .scheduled_event import * 3 | from .scheduled_instance import * 4 | from .system import * 5 | -------------------------------------------------------------------------------- /common/events/internal/scheduled_instance.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | "ScheduledInstance", 3 | ] 4 | 5 | from dataclasses import dataclass 6 | from datetime import datetime 7 | from uuid import UUID 8 | 9 | from common.entities import InstanceRuleAction 10 | from common.events.base import ProjectMixin 11 | 12 | 13 | @dataclass(kw_only=True) 14 | class ScheduledInstance(ProjectMixin): 15 | journey_id: UUID 16 | instance_rule_id: UUID 17 | instance_rule_action: InstanceRuleAction 18 | timestamp: datetime 19 | -------------------------------------------------------------------------------- /common/events/internal/system.py: -------------------------------------------------------------------------------- 1 | __all__ = ["AgentStatusChangeEvent"] 2 | 3 | from datetime import datetime 4 | from dataclasses import dataclass 5 | from uuid import UUID 6 | 7 | from common.entities.agent import AgentStatus 8 | from common.events.base import EventBaseMixin, ProjectMixin 9 | 10 | 11 | @dataclass(kw_only=True) 12 | class AgentStatusChangeEvent(EventBaseMixin, ProjectMixin): 13 | agent_id: UUID 14 | agent_key: str 15 | agent_tool: str 16 | previous_status: AgentStatus 17 | current_status: AgentStatus 18 | latest_heartbeat: datetime 19 | latest_event_timestamp: datetime 20 | -------------------------------------------------------------------------------- /common/events/v2/__init__.py: -------------------------------------------------------------------------------- 1 | from .base import * 2 | from .batch_pipeline_status import * 3 | from .component_data import * 4 | from .dataset_operation import * 5 | from .message_log import * 6 | from .metric_log import * 7 | from .test_outcomes import * 8 | from .testgen import * 9 | 10 | ALL_API_EVENT_SCHEMAS = [ 11 | BatchPipelineStatusSchema, 12 | DatasetOperationSchema, 13 | EventResponseSchema, 14 | MessageLogSchema, 15 | MetricLogSchema, 16 | TestOutcomesSchema, 17 | ] 18 | -------------------------------------------------------------------------------- /common/events/v2/helpers.py: -------------------------------------------------------------------------------- 1 | from common.entities import ApiEventType 2 | 3 | from .batch_pipeline_status import BatchPipelineStatusSchema 4 | from .dataset_operation import DatasetOperationSchema 5 | from .message_log import MessageLogSchema 6 | from .metric_log import MetricLogSchema 7 | from .test_outcomes import TestOutcomesSchema 8 | 9 | EVENT_TYPE_SCHEMAS = { 10 | ApiEventType.BATCH_PIPELINE_STATUS: BatchPipelineStatusSchema, 11 | ApiEventType.DATASET_OPERATION: DatasetOperationSchema, 12 | ApiEventType.MESSAGE_LOG: MessageLogSchema, 13 | ApiEventType.METRIC_LOG: MetricLogSchema, 14 | ApiEventType.TEST_OUTCOMES: TestOutcomesSchema, 15 | } 16 | -------------------------------------------------------------------------------- /common/exceptions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/exceptions/__init__.py -------------------------------------------------------------------------------- /common/exceptions/service.py: -------------------------------------------------------------------------------- 1 | class ServiceException(Exception): 2 | def __init__(self, msg: str) -> None: 3 | self.message = msg 4 | super().__init__(self.message) 5 | 6 | 7 | class MultipleActionsFound(ServiceException): 8 | pass 9 | -------------------------------------------------------------------------------- /common/kafka/__init__.py: -------------------------------------------------------------------------------- 1 | from .consumer import * 2 | from .errors import * 3 | from .message import * 4 | from .producer import * 5 | from .settings import * 6 | from .topic import * 7 | -------------------------------------------------------------------------------- /common/kafka/message.py: -------------------------------------------------------------------------------- 1 | __all__ = ["KafkaMessage"] 2 | from dataclasses import dataclass 3 | from typing import Generic, Optional, TypeVar 4 | 5 | T = TypeVar("T") 6 | 7 | 8 | @dataclass(frozen=True, kw_only=True) 9 | class KafkaMessage(Generic[T]): 10 | """ 11 | A generic Kafka message 12 | 13 | It is mainly used to convey payload and metadata info to consumers. The 14 | payload type is determined by the topic. 15 | """ 16 | 17 | payload: T 18 | topic: str 19 | partition: int 20 | offset: int 21 | headers: dict 22 | key: Optional[str] = None 23 | -------------------------------------------------------------------------------- /common/kubernetes/__init__.py: -------------------------------------------------------------------------------- 1 | from .readiness_probe import * 2 | -------------------------------------------------------------------------------- /common/logging/__init__.py: -------------------------------------------------------------------------------- 1 | from .json_logging import * 2 | -------------------------------------------------------------------------------- /common/peewee_extensions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/peewee_extensions/__init__.py -------------------------------------------------------------------------------- /common/peewee_extensions/templates/model.toml: -------------------------------------------------------------------------------- 1 | table_name = "{{ table_name }}" 2 | fixture_id = "{{ fixture_id }}"{% if requires %} 3 | requires_id = "{{ requires_id }}"{% endif %} 4 | {% for row in rows %} 5 | [[row]] 6 | {% for field, data in row.items() %}{% if data["value"] is not none %}{{ field }} = {{ data|toml_value }} 7 | {% endif %}{% endfor %}{% endfor %} 8 | -------------------------------------------------------------------------------- /common/predicate_engine/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/predicate_engine/__init__.py -------------------------------------------------------------------------------- /common/predicate_engine/exceptions.py: -------------------------------------------------------------------------------- 1 | class InvalidRuleData(ValueError): 2 | """Raised when attempting to compile rule data into a R object.""" 3 | -------------------------------------------------------------------------------- /common/predicate_engine/schemas/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/predicate_engine/schemas/__init__.py -------------------------------------------------------------------------------- /common/schemas/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/schemas/__init__.py -------------------------------------------------------------------------------- /common/schemas/fields/__init__.py: -------------------------------------------------------------------------------- 1 | from .cron_expr_str import * 2 | from .enum_str import * 3 | from .normalized_str import * 4 | from .zoneinfo import * 5 | -------------------------------------------------------------------------------- /common/schemas/validators/__init__.py: -------------------------------------------------------------------------------- 1 | from .not_empty import * 2 | from .regexp import * 3 | -------------------------------------------------------------------------------- /common/schemas/validators/not_empty.py: -------------------------------------------------------------------------------- 1 | __all__ = ["not_empty"] 2 | 3 | from functools import partial 4 | from collections.abc import Callable 5 | 6 | from marshmallow import validate 7 | 8 | not_empty: Callable = partial(validate.Length, min=1) 9 | """ 10 | A lot of times, we just want to validate that some message exists and is non-empty. Field classes such as 11 | Str class do not check the booleanness of a string, nor its length without a validator like this. As for why 12 | It's a partial like this; I thought it'd be more readable considering it's used so many places. 13 | """ 14 | -------------------------------------------------------------------------------- /common/schemas/validators/regexp.py: -------------------------------------------------------------------------------- 1 | __all__ = ["IsRegexp"] 2 | 3 | import re 4 | from typing import Optional 5 | 6 | from marshmallow import ValidationError 7 | from marshmallow.validate import Validator 8 | 9 | 10 | class IsRegexp(Validator): 11 | """ 12 | Validates the input string is a regular expression. 13 | """ 14 | 15 | message_invalid = "Invalid regular expression" 16 | 17 | def __init__(self, *, error: Optional[str] = None) -> None: 18 | self.error: str = error or self.message_invalid 19 | 20 | def __call__(self, value: str) -> str: 21 | try: 22 | re.compile(value) 23 | except Exception as e: 24 | raise ValidationError(self.error.format(input=value)) from e 25 | return value 26 | -------------------------------------------------------------------------------- /common/sentinel.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class Sentinel(Enum): 5 | """Sentinel object (as Enum for type checking unless PEP-661 is ever approved).""" 6 | 7 | _ = object() 8 | 9 | 10 | SENTINEL = Sentinel._ 11 | -------------------------------------------------------------------------------- /common/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/__init__.py -------------------------------------------------------------------------------- /common/tests/fake_models/__init__.py: -------------------------------------------------------------------------------- 1 | """Fake models module for testing.""" 2 | -------------------------------------------------------------------------------- /common/tests/fake_models/model_a.py: -------------------------------------------------------------------------------- 1 | from peewee import CharField, Model 2 | 3 | 4 | class FakeModelA(Model): 5 | foo = CharField() 6 | bar = CharField() 7 | -------------------------------------------------------------------------------- /common/tests/fake_models/model_b.py: -------------------------------------------------------------------------------- 1 | from peewee import CharField, Model 2 | 3 | 4 | class FakeModelB(Model): 5 | fizz = CharField() 6 | buzz = CharField() 7 | -------------------------------------------------------------------------------- /common/tests/integration/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/integration/__init__.py -------------------------------------------------------------------------------- /common/tests/integration/actions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/integration/actions/__init__.py -------------------------------------------------------------------------------- /common/tests/integration/actions/test_action_factory.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from common.actions.action_factory import ACTION_CLASS_MAP 4 | from common.schemas.action_schemas import ValidActions 5 | 6 | 7 | @pytest.mark.integration 8 | def test_check_all_action_implemented(): 9 | # Check that valid actions are represented in the action factory map and vice versa. 10 | assert ACTION_CLASS_MAP.keys() == set(a.name for a in ValidActions) 11 | -------------------------------------------------------------------------------- /common/tests/integration/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/integration/api/__init__.py -------------------------------------------------------------------------------- /common/tests/integration/auth/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/integration/auth/__init__.py -------------------------------------------------------------------------------- /common/tests/integration/auth/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from peewee import SqliteDatabase 3 | 4 | from common.entities import ALL_MODELS, DB 5 | 6 | 7 | @pytest.fixture 8 | def test_db(): 9 | DB.initialize(SqliteDatabase(":memory:", pragmas={"foreign_keys": 1})) 10 | yield DB 11 | 12 | 13 | @pytest.fixture(autouse=True) 14 | def test_base(test_db): 15 | test_db.create_tables(ALL_MODELS) 16 | yield 17 | test_db.drop_tables(ALL_MODELS) 18 | test_db.close() 19 | -------------------------------------------------------------------------------- /common/tests/integration/email/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/integration/email/__init__.py -------------------------------------------------------------------------------- /common/tests/integration/entities/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/integration/entities/__init__.py -------------------------------------------------------------------------------- /common/tests/integration/entities/test_dataset_operation.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | import pytest 4 | 5 | from common.entities import DatasetOperation, DatasetOperationType 6 | 7 | 8 | @pytest.mark.integration 9 | def test_dataset_operation_create(dataset, instance_set): 10 | DatasetOperation.create( 11 | dataset=dataset, 12 | instance_set=instance_set, 13 | operation=DatasetOperationType.WRITE, 14 | operation_time=datetime.utcnow(), 15 | ) 16 | -------------------------------------------------------------------------------- /common/tests/integration/entities/test_rule.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from common.entities import Rule 4 | 5 | 6 | @pytest.mark.integration 7 | def test_rule_create(action, pipeline, journey): 8 | Rule.create( 9 | name="test rule", 10 | journey=journey, 11 | rule_schema="fake schema", 12 | rule_data="fake data", 13 | action=action, 14 | component=pipeline, 15 | ) 16 | 17 | 18 | @pytest.mark.integration 19 | def test_rule_defaults(action, journey): 20 | rule = Rule.create( 21 | name="test rule", rule_schema="fake schema", rule_data="fake data", action=action, journey=journey 22 | ) 23 | assert rule.action_args == {} 24 | -------------------------------------------------------------------------------- /common/tests/integration/entities/test_schedule.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from common.entities import Schedule, ScheduleExpectation 4 | 5 | 6 | @pytest.mark.integration 7 | def test_schedule_create(pipeline): 8 | Schedule.create( 9 | component=pipeline, 10 | description="Some cool schedule", 11 | schedule="25 */2 * * *", 12 | timezone="EST", 13 | expectation=ScheduleExpectation.BATCH_PIPELINE_START_TIME.value, 14 | margin=120, 15 | ) 16 | -------------------------------------------------------------------------------- /common/tests/integration/entities/test_user.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from common.entities import Company, Role, User, UserRole 4 | 5 | 6 | @pytest.mark.integration 7 | def test_user_has_role_on(): 8 | company = Company.create(name="Foo") 9 | user = User.create(name="Not Max", email="bar", foreign_user_id="def", primary_company=company) 10 | role = Role.create(name="test-user-role") 11 | UserRole.create(user=user, role=role) 12 | assert user.has_role("test-user-role") is True 13 | assert user.has_role("this-role-no-existy") is False 14 | -------------------------------------------------------------------------------- /common/tests/integration/entity_services/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/integration/entity_services/__init__.py -------------------------------------------------------------------------------- /common/tests/integration/events/conftest.py: -------------------------------------------------------------------------------- 1 | from testlib.fixtures.v1_events import * 2 | -------------------------------------------------------------------------------- /common/tests/integration/flask_ext/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/integration/flask_ext/__init__.py -------------------------------------------------------------------------------- /common/tests/integration/peewee_extensions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/integration/peewee_extensions/__init__.py -------------------------------------------------------------------------------- /common/tests/integration/peewee_extensions/bad_fixtures/company.toml: -------------------------------------------------------------------------------- 1 | table_name = "company" 2 | # NOTE: This is a cyclic dependency. 3 | fixture_id = "9da3a73e-ac41-4ef3-9527-0bee2cb1232d" 4 | requires_id = "7030ed67-1fdd-4d7e-8ca0-f758599600b6" 5 | 6 | [[row]] 7 | id = "3f49acf2-327d-4b20-bf24-6801ea9013ed" 8 | active = true 9 | created_on = "2022-06-22T17:46:36.479602+00:00" 10 | name = "LiteralKitchen" 11 | -------------------------------------------------------------------------------- /common/tests/integration/peewee_extensions/bad_fixtures/organization.toml: -------------------------------------------------------------------------------- 1 | table_name = "organization" 2 | fixture_id = "7030ed67-1fdd-4d7e-8ca0-f758599600b6" 3 | requires_id = "9da3a73e-ac41-4ef3-9527-0bee2cb1232d" 4 | 5 | 6 | [[row]] 7 | id = "ea8af577-d714-4804-822a-f002434a2b1a" 8 | created_on = "2022-06-22T17:46:14.097997+00:00" 9 | name = "default" 10 | description = """ 11 | This is a cool place to be I guess.""" 12 | company = "3f49acf2-327d-4b20-bf24-6801ea9013ed" 13 | active = true 14 | -------------------------------------------------------------------------------- /common/tests/integration/peewee_extensions/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from peewee import SqliteDatabase 3 | 4 | from common.entities import ALL_MODELS, DB 5 | 6 | 7 | @pytest.fixture 8 | def test_db_base(): 9 | DB.initialize(SqliteDatabase(":memory:", pragmas={"foreign_keys": 1})) 10 | yield DB 11 | DB.obj = None 12 | 13 | 14 | @pytest.fixture 15 | def test_db(test_db_base): 16 | test_db_base.create_tables(ALL_MODELS) 17 | yield 18 | test_db_base.drop_tables(ALL_MODELS) 19 | test_db_base.close() 20 | -------------------------------------------------------------------------------- /common/tests/integration/peewee_extensions/fixtures/company.toml: -------------------------------------------------------------------------------- 1 | table_name = "company" 2 | fixture_id = "9da3a73e-ac41-4ef3-9527-0bee2cb1232d" 3 | 4 | [[row]] 5 | id = "3f49acf2-327d-4b20-bf24-6801ea9013ed" 6 | created_on = 1672179122156235 7 | name = "LiteralKitchen" 8 | -------------------------------------------------------------------------------- /common/tests/integration/peewee_extensions/fixtures/organization.toml: -------------------------------------------------------------------------------- 1 | table_name = "organization" 2 | fixture_id = "7030ed67-1fdd-4d7e-8ca0-f758599600b6" 3 | requires_id = "9da3a73e-ac41-4ef3-9527-0bee2cb1232d" 4 | 5 | [[row]] 6 | id = "a80e6e65-e268-447b-aaef-68057915a7ef" 7 | created_on = 1672179122156235 8 | name = "default" 9 | description = """ 10 | This is a cool place to be I guess.""" 11 | company = "3f49acf2-327d-4b20-bf24-6801ea9013ed" 12 | -------------------------------------------------------------------------------- /common/tests/integration/peewee_extensions/fixtures/project.toml: -------------------------------------------------------------------------------- 1 | table_name = "project" 2 | fixture_id = "70fe8951-d433-426d-8c08-5ca96117f740" 3 | requires_id = "7030ed67-1fdd-4d7e-8ca0-f758599600b6" 4 | 5 | [[row]] 6 | id = "9fbee19e-5319-4366-b4b8-b3c589525297" 7 | active = true 8 | created_on = 1672179122156235 9 | name = "default" 10 | organization = "a80e6e65-e268-447b-aaef-68057915a7ef" 11 | -------------------------------------------------------------------------------- /common/tests/integration/peewee_extensions/fixtures/service-account-key.toml: -------------------------------------------------------------------------------- 1 | table_name = "service_account_key" 2 | fixture_id = "bed70422-32de-40f4-a781-555e4238e11d" 3 | requires_id = "70fe8951-d433-426d-8c08-5ca96117f740" 4 | 5 | [[row]] 6 | digest = "gmuIsKVv1TfN/hU1TvS+/fFZXs/e1HCEeu+0x6pcF3l8MzkwMDAwfDkzNTYxMTQxLTZmZjgtNGRiNi1hMjY4LTk4ZDA4MzczYzQzYQ==" 7 | expiry = 1690981384890272 8 | id = "c780843a-ea7d-47da-8aaf-d3eed3e53e9b" 9 | project = "9fbee19e-5319-4366-b4b8-b3c589525297" 10 | allowed_services = '["EVENTS_API"]' 11 | name = "Default" 12 | -------------------------------------------------------------------------------- /common/tests/unit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/__init__.py -------------------------------------------------------------------------------- /common/tests/unit/actions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/actions/__init__.py -------------------------------------------------------------------------------- /common/tests/unit/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/api/__init__.py -------------------------------------------------------------------------------- /common/tests/unit/auth/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/auth/__init__.py -------------------------------------------------------------------------------- /common/tests/unit/constants/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/constants/__init__.py -------------------------------------------------------------------------------- /common/tests/unit/constants/test_schema_validation.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | import pytest 4 | 5 | from common.constants import EXTENDED_ALPHANUMERIC_REGEX 6 | 7 | 8 | @pytest.mark.unit 9 | @pytest.mark.parametrize("value", ("", " ", "z", "åêà", "aA1", "b B", " c ", "d_D", "123_abc 456 EDF")) 10 | def test_extended_alphanumeric_regex_matching(value): 11 | assert re.match(EXTENDED_ALPHANUMERIC_REGEX, value) 12 | 13 | 14 | @pytest.mark.unit 15 | @pytest.mark.parametrize("value", ("!", "_", "_a", "b_c-d")) 16 | def test_extended_alphanumeric_regex_not_matching(value): 17 | assert not re.match(EXTENDED_ALPHANUMERIC_REGEX, value) 18 | -------------------------------------------------------------------------------- /common/tests/unit/email/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/email/__init__.py -------------------------------------------------------------------------------- /common/tests/unit/entities/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/entities/__init__.py -------------------------------------------------------------------------------- /common/tests/unit/entity_services/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/entity_services/__init__.py -------------------------------------------------------------------------------- /common/tests/unit/entity_services/helpers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/entity_services/helpers/__init__.py -------------------------------------------------------------------------------- /common/tests/unit/events/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/events/__init__.py -------------------------------------------------------------------------------- /common/tests/unit/events/v1/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/events/v1/__init__.py -------------------------------------------------------------------------------- /common/tests/unit/events/v1/conftest.py: -------------------------------------------------------------------------------- 1 | from testlib.fixtures.v1_events import * 2 | -------------------------------------------------------------------------------- /common/tests/unit/events/v1/test_event_schemas.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import pytest 4 | 5 | from common.events.v1 import EventSchema 6 | 7 | 8 | @pytest.mark.unit 9 | def test_decode_bytes_with_dict(event_data): 10 | EventSchema().load(event_data) 11 | 12 | 13 | @pytest.mark.unit 14 | def test_decode_bytes_with_bytes(event_data): 15 | EventSchema().load(json.dumps(event_data).encode("utf-8")) 16 | -------------------------------------------------------------------------------- /common/tests/unit/flask_ext/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/flask_ext/__init__.py -------------------------------------------------------------------------------- /common/tests/unit/flask_ext/conftest.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/flask_ext/conftest.py -------------------------------------------------------------------------------- /common/tests/unit/flask_ext/test_cors.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from flask import Response 3 | 4 | from common.api.flask_ext.cors import CORS, CORS_HEADERS 5 | 6 | CORS_HEADER_TUPLE: tuple[str, ...] = tuple(CORS_HEADERS.keys()) 7 | 8 | 9 | @pytest.mark.unit 10 | def test_headers_added(): 11 | response = Response() 12 | CORS.set_cors_headers(response) 13 | for header_name in CORS_HEADER_TUPLE: 14 | assert header_name in response.headers 15 | -------------------------------------------------------------------------------- /common/tests/unit/kafka/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/kafka/__init__.py -------------------------------------------------------------------------------- /common/tests/unit/kubernetes/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/kubernetes/__init__.py -------------------------------------------------------------------------------- /common/tests/unit/logging/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/logging/__init__.py -------------------------------------------------------------------------------- /common/tests/unit/peewee_extensions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/peewee_extensions/__init__.py -------------------------------------------------------------------------------- /common/tests/unit/predicate_engine/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/predicate_engine/__init__.py -------------------------------------------------------------------------------- /common/tests/unit/schemas/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/schemas/__init__.py -------------------------------------------------------------------------------- /common/tests/unit/schemas/fields/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/schemas/fields/__init__.py -------------------------------------------------------------------------------- /common/tests/unit/schemas/validators/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/tests/unit/schemas/validators/__init__.py -------------------------------------------------------------------------------- /common/typing.py: -------------------------------------------------------------------------------- 1 | """A module for custom type definitions.""" 2 | 3 | JWT_CLAIMS = dict[str, object] 4 | """Type for decoded JWT token.""" 5 | -------------------------------------------------------------------------------- /common/user_strings/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/common/user_strings/__init__.py -------------------------------------------------------------------------------- /conf/defaults.py: -------------------------------------------------------------------------------- 1 | RULE_REFRESH_SECONDS: int = 30 2 | """Number of seconds to cache rules in rules engine""" 3 | 4 | 5 | MIGRATIONS_SRC_PATH = "/dk/lib/migrations" 6 | """Yoyo migrations source folder.""" 7 | 8 | AGENT_STATUS_CHECK_DEFAULT_INTERVAL_SECONDS: int = 300 9 | """Default polling internal for Agent status changes.""" 10 | 11 | AGENT_STATUS_CHECK_UNHEALTHY_FACTOR: float = 2 12 | """Multiplier factor to consider an Agent unhealthy, based on the checking interval.""" 13 | 14 | AGENT_STATUS_CHECK_OFFLINE_FACTOR: float = 4 15 | """Multiplier factor to consider an Agent offline, based on the checking interval.""" 16 | -------------------------------------------------------------------------------- /conf/local.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | from peewee import SqliteDatabase 4 | 5 | PROJECT_ROOT = Path(__file__).parent.parent 6 | 7 | DATABASE: dict[str, object] = { 8 | "name": PROJECT_ROOT.joinpath("test.db"), 9 | "engine": SqliteDatabase, 10 | "pragmas": { 11 | "journal_mode": "wal", 12 | "cache_size": -1, # 10000 pages, or ~40MB 13 | "foreign_keys": 1, # Enforce foreign-key constraints 14 | "ignore_check_constraints": 0, # enforce CHECK constraints 15 | "case_sensitive_like": True, # Case sensitive queries 16 | }, 17 | } 18 | """Settings for a local sqlite database running locally.""" 19 | -------------------------------------------------------------------------------- /conf/test.py: -------------------------------------------------------------------------------- 1 | from peewee import SqliteDatabase 2 | 3 | DATABASE: dict[str, object] = { 4 | "name": "file:cachedb?mode=memory&cache=shared", 5 | "engine": SqliteDatabase, 6 | "pragmas": {"foreign_keys": 1}, 7 | "uri": True, 8 | } 9 | """Configures an in-memory database with a shared cache for testing.""" 10 | 11 | KAFKA_CONNECTION_PARAMS: dict[str, str] = {} 12 | """Empty Kafka connect parameters to please unit tests.""" 13 | 14 | SMTP: dict[str, object] = { 15 | "username": "", 16 | "password": "", 17 | "endpoint": "", 18 | "port": 25, 19 | "from_address": "", 20 | } 21 | """Dummy SMTP parameters to please unit tests.""" 22 | -------------------------------------------------------------------------------- /conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import pytest 4 | 5 | 6 | def pytest_configure(config: pytest.Config) -> None: 7 | os.environ["OBSERVABILITY_CONFIG"] = "test" 8 | -------------------------------------------------------------------------------- /deploy/charts/observability-app/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: dataops-observability-app 3 | type: application 4 | appVersion: "2.x.x" 5 | version: "2.2.4" 6 | 7 | description: DataOps Observability 8 | home: https://datakitchen.io 9 | icon: https://cloud.datakitchen.io/assets/image/dk-logo.svg 10 | keywords: 11 | - datakitchen 12 | - dataops 13 | maintainers: 14 | - name: DataKitchen 15 | url: https://datakitchen.io 16 | -------------------------------------------------------------------------------- /deploy/charts/observability-app/templates/_probes.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Command-based readiness probe 3 | */}} 4 | 5 | {{- define "observability.probes.readiness_cmd" -}} 6 | readinessProbe: 7 | exec: 8 | command: 9 | - /dk/bin/{{ . }} 10 | - --check-ready 11 | # We are not polling this too often and also have a generous timeout because the check ready action waits the ready 12 | # condition to be reached when the service is not ready right away. This allows us to have a tight switch to the 13 | # new pod, potentially reducing the overall deployment time 14 | periodSeconds: 30 15 | timeoutSeconds: 60 16 | {{- end -}} 17 | -------------------------------------------------------------------------------- /deploy/charts/observability-app/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "observability.serviceAccountName" . }} 6 | labels: 7 | {{- include "observability.labels" . | nindent 4 }} 8 | {{- with .Values.serviceAccount.annotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /deploy/charts/observability-services/Chart.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: kafka 3 | repository: https://charts.bitnami.com/bitnami 4 | version: 20.0.4 5 | - name: mysql 6 | repository: https://charts.bitnami.com/bitnami 7 | version: 9.4.5 8 | digest: sha256:e1ce9f0395b3c90bffe9f3fc989ba4b0deeec7cb0d101d0624523ac44bc89271 9 | generated: "2024-01-17T21:52:57.718202-05:00" 10 | -------------------------------------------------------------------------------- /deploy/charts/observability-services/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: dataops-observability-services 3 | type: application 4 | appVersion: "2.x.x" 5 | version: "2.0.2" 6 | 7 | dependencies: 8 | - name: kafka 9 | version: 20.0.4 10 | repository: https://charts.bitnami.com/bitnami 11 | condition: kafka.enable 12 | - name: mysql 13 | version: 9.4.5 14 | repository: https://charts.bitnami.com/bitnami 15 | condition: mysql.enable 16 | 17 | description: DataOps Observability Supporting Services 18 | home: https://datakitchen.io 19 | icon: https://cloud.datakitchen.io/assets/image/dk-logo.svg 20 | keywords: 21 | - datakitchen 22 | - dataops 23 | maintainers: 24 | - name: DataKitchen 25 | url: https://datakitchen.io 26 | -------------------------------------------------------------------------------- /deploy/charts_values/values-services-dev.yaml: -------------------------------------------------------------------------------- 1 | kafka: 2 | externalAccess: 3 | enabled: true 4 | service: 5 | type: NodePort 6 | useHostIPs: true 7 | nodePorts: [9092] 8 | 9 | mysql: 10 | primary: 11 | service: 12 | type: NodePort 13 | nodePorts: 14 | mysql: 3306 15 | -------------------------------------------------------------------------------- /deploy/conf/gunicorn.conf.py: -------------------------------------------------------------------------------- 1 | workers = 2 2 | theads = 16 3 | -------------------------------------------------------------------------------- /deploy/conf/yoyo.ini: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | sources = /dk/lib/migrations 3 | batch_mode = off 4 | verbosity = 2 5 | database = mysql://%(MYSQL_USER)s:%(MYSQL_PASSWORD)s@%(MYSQL_SERVICE_HOST)s:%(MYSQL_SERVICE_PORT)s/%(MYSQL_DATABASE)s 6 | -------------------------------------------------------------------------------- /deploy/migrations/20240627_01_bgIWR-adding-agent-status-column.py: -------------------------------------------------------------------------------- 1 | """ 2 | Adding agent status column 3 | """ 4 | 5 | from yoyo import step 6 | 7 | __depends__ = {"20240605_01_vjN7f-initial-schema"} 8 | __transactional__ = False 9 | 10 | steps = [ 11 | step( 12 | "ALTER TABLE `agent` ADD COLUMN `status` varchar(20) NOT NULL", 13 | "ALTER TABLE `agent` DROP COLUMN `status`", 14 | ), 15 | ] 16 | -------------------------------------------------------------------------------- /deploy/migrations/20240627_02_ORQ6B-adding-agent-status-check-config-column.py: -------------------------------------------------------------------------------- 1 | """ 2 | Adding agent status check config column 3 | """ 4 | 5 | from yoyo import step 6 | 7 | __depends__ = {"20240627_01_bgIWR-adding-agent-status-column"} 8 | __transactional__ = False 9 | 10 | steps = [ 11 | step( 12 | "ALTER TABLE `project` ADD COLUMN `agent_status_check_interval` INT NOT NULL", 13 | "ALTER TABLE `project` DROP COLUMN `agent_status_check_interval`", 14 | ), 15 | ] 16 | -------------------------------------------------------------------------------- /deploy/migrations/20240627_03_4o7tH-agent-status-check-default-values.py: -------------------------------------------------------------------------------- 1 | """ 2 | Agent status check default values 3 | """ 4 | 5 | from yoyo import step 6 | 7 | __depends__ = {"20240627_02_ORQ6B-adding-agent-status-check-config-column"} 8 | 9 | steps = [ 10 | step("UPDATE `project` SET `agent_status_check_interval` = 300"), 11 | step("UPDATE `agent` SET `status` = 'ONLINE'"), 12 | ] 13 | -------------------------------------------------------------------------------- /deploy/migrations/20240701_01_zRe7i-add-project-alert-config-field.py: -------------------------------------------------------------------------------- 1 | """ 2 | Add project alert config field 3 | """ 4 | 5 | from yoyo import step 6 | 7 | __depends__ = {"20240627_03_4o7tH-agent-status-check-default-values"} 8 | __transactional__ = False 9 | 10 | steps = [ 11 | step( 12 | "ALTER TABLE `project` ADD COLUMN `alert_actions` JSON NOT NULL", 13 | "ALTER TABLE `project` DROP COLUMN `alert_actions`", 14 | ) 15 | ] 16 | -------------------------------------------------------------------------------- /deploy/migrations/20240705_01_37l4A-set-project-alert-config-default.py: -------------------------------------------------------------------------------- 1 | """ 2 | Set project alert config default 3 | """ 4 | 5 | from yoyo import step 6 | 7 | __depends__ = {"20240701_01_zRe7i-add-project-alert-config-field"} 8 | 9 | steps = [ 10 | step("UPDATE `project` SET `alert_actions` = JSON_ARRAY()"), 11 | ] 12 | -------------------------------------------------------------------------------- /deploy/migrations/20240723_01_K3c3Q-renaming-the-agent-check-interval-column.py: -------------------------------------------------------------------------------- 1 | """ 2 | Renaming the agent check interval column 3 | """ 4 | 5 | from yoyo import step 6 | 7 | __depends__ = {"20240705_01_37l4A-set-project-alert-config-default"} 8 | 9 | steps = [ 10 | step( 11 | "ALTER TABLE `project` RENAME COLUMN `agent_status_check_interval` TO `agent_check_interval`", 12 | "ALTER TABLE `project` RENAME COLUMN `agent_check_interval` TO `agent_status_check_interval`", 13 | ), 14 | ] 15 | -------------------------------------------------------------------------------- /event_api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/event_api/__init__.py -------------------------------------------------------------------------------- /event_api/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/event_api/config/__init__.py -------------------------------------------------------------------------------- /event_api/config/cloud.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | # Flask specific settings: https://flask.palletsprojects.com/en/latest/config/#builtin-configuration-values 4 | SECRET_KEY: str = os.environ["EVENTS_KEY_FLASK_SECRET"] 5 | SERVER_NAME: str = os.environ["EVENTS_API_HOSTNAME"] 6 | -------------------------------------------------------------------------------- /event_api/config/local.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | # Flask specific settings: https://flask.palletsprojects.com/en/latest/config/#builtin-configuration-values 4 | PROPAGATE_EXCEPTIONS: Optional[bool] = True 5 | SECRET_KEY: str = "NOT_VERY_SECRET" 6 | -------------------------------------------------------------------------------- /event_api/config/minikube.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | # Flask specific settings: https://flask.palletsprojects.com/en/latest/config/#builtin-configuration-values 4 | TESTING: Optional[bool] = True 5 | SECRET_KEY: str = "NOT_VERY_SECRET" 6 | -------------------------------------------------------------------------------- /event_api/config/test.py: -------------------------------------------------------------------------------- 1 | from peewee import SqliteDatabase 2 | 3 | DATABASE = { 4 | "name": "file:cachedb?mode=memory&cache=shared", 5 | "engine": SqliteDatabase, 6 | "pragmas": {}, 7 | } 8 | """Configures an in-memory database with a shared cache for testing.""" 9 | 10 | API_PREFIX: str = "events" 11 | 12 | TESTING: bool = True 13 | """Enable flask TESTING mode. This is needed to get around the default-key security check.""" 14 | -------------------------------------------------------------------------------- /event_api/endpoints/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/event_api/endpoints/__init__.py -------------------------------------------------------------------------------- /event_api/endpoints/v1/__init__.py: -------------------------------------------------------------------------------- 1 | from .dataset_operation import * 2 | from .message_log import * 3 | from .metric_log import * 4 | from .run_status import * 5 | from .test_outcomes import * 6 | -------------------------------------------------------------------------------- /event_api/endpoints/v2/__init__.py: -------------------------------------------------------------------------------- 1 | from .batch_pipeline_status import * 2 | from .dataset_operation import * 3 | from .event_view import * 4 | from .message_log import * 5 | from .metric_log import * 6 | from .test_outcomes import * 7 | -------------------------------------------------------------------------------- /event_api/helpers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/event_api/helpers/__init__.py -------------------------------------------------------------------------------- /event_api/helpers/health.py: -------------------------------------------------------------------------------- 1 | from common.entities import DB 2 | from common.kafka import TOPIC_UNIDENTIFIED_EVENTS, KafkaProducer 3 | from common.kubernetes.readiness_probe import NotReadyException 4 | 5 | 6 | def readiness_probe() -> None: 7 | if DB.obj is None: 8 | raise NotReadyException("Database not initialized") 9 | with KafkaProducer({}) as producer: 10 | if not producer.is_topic_available(TOPIC_UNIDENTIFIED_EVENTS): 11 | raise NotReadyException("Kafka topic not ready or producer not connected") 12 | -------------------------------------------------------------------------------- /event_api/routes/__init__.py: -------------------------------------------------------------------------------- 1 | from .v1_routes import * 2 | from .v2_routes import * 3 | -------------------------------------------------------------------------------- /event_api/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/event_api/tests/__init__.py -------------------------------------------------------------------------------- /event_api/tests/integration/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/event_api/tests/integration/__init__.py -------------------------------------------------------------------------------- /event_api/tests/integration/v1_endpoints/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/event_api/tests/integration/v1_endpoints/__init__.py -------------------------------------------------------------------------------- /event_api/tests/integration/v2_endpoints/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/event_api/tests/integration/v2_endpoints/__init__.py -------------------------------------------------------------------------------- /event_api/tests/unit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/event_api/tests/unit/__init__.py -------------------------------------------------------------------------------- /observability_api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_api/__init__.py -------------------------------------------------------------------------------- /observability_api/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_api/config/__init__.py -------------------------------------------------------------------------------- /observability_api/config/cloud.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | # Flask specific settings: https://flask.palletsprojects.com/en/latest/config/#builtin-configuration-values 4 | SECRET_KEY: str = os.environ["OBSERVABILITY_KEY_FLASK_SECRET"] 5 | SERVER_NAME: str = os.environ["OBSERVABILITY_API_HOSTNAME"] 6 | 7 | try: 8 | DEFAULT_JWT_EXPIRATION_SECONDS: float = float(os.environ["OBSERVABILITY_JWT_EXPIRATION_SECONDS"]) 9 | except Exception: 10 | pass 11 | -------------------------------------------------------------------------------- /observability_api/config/local.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | # Flask specific settings: https://flask.palletsprojects.com/en/latest/config/#builtin-configuration-values 4 | PROPAGATE_EXCEPTIONS: Optional[bool] = True 5 | SECRET_KEY: str = "NOT_VERY_SECRET" 6 | 7 | # Application settings 8 | OAUTHLIB_INSECURE_TRANSPORT: bool = True 9 | """Determines whether or not to allow single-sign-on flow when not using https.""" 10 | -------------------------------------------------------------------------------- /observability_api/config/minikube.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | # Flask specific settings: https://flask.palletsprojects.com/en/latest/config/#builtin-configuration-values 4 | TESTING: Optional[bool] = True 5 | SECRET_KEY: str = "NOT_VERY_SECRET" 6 | 7 | # Application settings 8 | OAUTHLIB_INSECURE_TRANSPORT: bool = True 9 | """Determines whether or not to allow single-sign-on flow when not using https.""" 10 | -------------------------------------------------------------------------------- /observability_api/config/test.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | # Flask specific settings: https://flask.palletsprojects.com/en/latest/config/#builtin-configuration-values 4 | PROPAGATE_EXCEPTIONS: Optional[bool] = True 5 | SECRET_KEY: str = "NOT_VERY_SECRET" 6 | TESTING: bool = True 7 | 8 | # Application settings 9 | OAUTHLIB_INSECURE_TRANSPORT: bool = True 10 | """Determines whether or not to allow single-sign-on flow when not using https.""" 11 | -------------------------------------------------------------------------------- /observability_api/endpoints/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_api/endpoints/__init__.py -------------------------------------------------------------------------------- /observability_api/endpoints/v1/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_api/endpoints/v1/__init__.py -------------------------------------------------------------------------------- /observability_api/helpers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_api/helpers/__init__.py -------------------------------------------------------------------------------- /observability_api/helpers/health.py: -------------------------------------------------------------------------------- 1 | from common.entities import DB 2 | 3 | 4 | def readiness_probe() -> None: 5 | if DB.obj is None: 6 | raise ValueError("Database not initialized") 7 | -------------------------------------------------------------------------------- /observability_api/routes/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ["build_v1_routes"] 2 | 3 | from .v1_routes import build_v1_routes 4 | -------------------------------------------------------------------------------- /observability_api/schemas/base_schemas.py: -------------------------------------------------------------------------------- 1 | __all__ = ["AuditEntitySchemaMixin", "BaseEntitySchema"] 2 | from marshmallow.fields import UUID, DateTime, Nested 3 | from marshmallow_peewee import ModelSchema 4 | 5 | from common.entities import BaseEntity, User 6 | 7 | 8 | class BaseEntitySchema(ModelSchema): 9 | id = UUID(dump_only=True) 10 | 11 | class Meta: 12 | model = BaseEntity 13 | 14 | 15 | class AuditUserSchema(BaseEntitySchema): 16 | class Meta: 17 | model = User 18 | fields = ("id", "name") 19 | 20 | 21 | class AuditEntitySchemaMixin: 22 | created_on = DateTime(dump_only=True) 23 | created_by = Nested(AuditUserSchema(), dump_only=True) 24 | -------------------------------------------------------------------------------- /observability_api/schemas/company_schemas.py: -------------------------------------------------------------------------------- 1 | __all__ = ["CompanySchema", "CompanyPatchSchema"] 2 | 3 | from common.entities import Company 4 | 5 | from .base_schemas import AuditEntitySchemaMixin, BaseEntitySchema 6 | 7 | 8 | class CompanySchema(BaseEntitySchema, AuditEntitySchemaMixin): 9 | class Meta: 10 | model = Company 11 | 12 | 13 | class CompanyPatchSchema(CompanySchema): 14 | class Meta: 15 | fields = ("name",) 16 | -------------------------------------------------------------------------------- /observability_api/schemas/organization_schemas.py: -------------------------------------------------------------------------------- 1 | __all__ = ["OrganizationSchema", "OrganizationPatchSchema"] 2 | from marshmallow.fields import Pluck 3 | 4 | from common.entities import Organization 5 | 6 | from .base_schemas import AuditEntitySchemaMixin, BaseEntitySchema 7 | from .company_schemas import CompanySchema 8 | 9 | 10 | class OrganizationSchema(BaseEntitySchema, AuditEntitySchemaMixin): 11 | company = Pluck(CompanySchema, "id", dump_only=True) 12 | 13 | class Meta: 14 | model = Organization 15 | 16 | 17 | class OrganizationPatchSchema(OrganizationSchema): 18 | class Meta: 19 | fields = ("name", "description") 20 | -------------------------------------------------------------------------------- /observability_api/schemas/pipeline_schemas.py: -------------------------------------------------------------------------------- 1 | __all__ = ["PipelineSchema"] 2 | 3 | from common.entities.component import ComponentType 4 | from common.schemas.fields import EnumStr 5 | from observability_api.schemas import ComponentSchema 6 | 7 | 8 | class PipelineSchema(ComponentSchema): 9 | type = EnumStr( 10 | enum=ComponentType, 11 | load_default=ComponentType.BATCH_PIPELINE.value, 12 | dump_default=ComponentType.BATCH_PIPELINE.value, 13 | ) 14 | -------------------------------------------------------------------------------- /observability_api/schemas/project_schemas.py: -------------------------------------------------------------------------------- 1 | __all__ = ["ProjectSchema", "ProjectPatchSchema"] 2 | 3 | from marshmallow.fields import Pluck 4 | 5 | from common.entities import Project 6 | 7 | from .base_schemas import AuditEntitySchemaMixin, BaseEntitySchema 8 | from .organization_schemas import OrganizationSchema 9 | 10 | 11 | class ProjectSchema(BaseEntitySchema, AuditEntitySchemaMixin): 12 | organization = Pluck(OrganizationSchema, "id", dump_only=True) 13 | 14 | class Meta: 15 | model = Project 16 | exclude = ("agent_check_interval", "alert_actions") 17 | 18 | 19 | class ProjectPatchSchema(ProjectSchema): 20 | class Meta: 21 | fields = ("name", "description", "active") 22 | -------------------------------------------------------------------------------- /observability_api/schemas/server_schemas.py: -------------------------------------------------------------------------------- 1 | __all__ = ["ServerSchema"] 2 | 3 | from common.entities.component import ComponentType 4 | from common.schemas.fields import EnumStr 5 | from observability_api.schemas import ComponentSchema 6 | 7 | 8 | class ServerSchema(ComponentSchema): 9 | type = EnumStr( 10 | enum=ComponentType, 11 | load_default=ComponentType.SERVER.value, 12 | dump_default=ComponentType.SERVER.value, 13 | ) 14 | -------------------------------------------------------------------------------- /observability_api/schemas/streaming_pipeline_schemas.py: -------------------------------------------------------------------------------- 1 | __all__ = ["StreamingPipelineSchema"] 2 | 3 | from common.entities.component import ComponentType 4 | from common.schemas.fields import EnumStr 5 | from observability_api.schemas import ComponentSchema 6 | 7 | 8 | class StreamingPipelineSchema(ComponentSchema): 9 | type = EnumStr( 10 | enum=ComponentType, 11 | load_default=ComponentType.STREAMING_PIPELINE.value, 12 | dump_default=ComponentType.STREAMING_PIPELINE.value, 13 | ) 14 | -------------------------------------------------------------------------------- /observability_api/schemas/testgen_dataset_component_schemas.py: -------------------------------------------------------------------------------- 1 | __all__ = ["TestgenDatasetComponentSchema"] 2 | 3 | from marshmallow.fields import List, Str 4 | 5 | from common.entities import TestgenDatasetComponent 6 | from observability_api.schemas.base_schemas import BaseEntitySchema 7 | 8 | 9 | class TestgenDatasetComponentSchema(BaseEntitySchema): 10 | table_list = List(Str()) 11 | integration_name = Str(dump_only=True, dump_default="TESTGEN") 12 | 13 | class Meta: 14 | model = TestgenDatasetComponent 15 | -------------------------------------------------------------------------------- /observability_api/schemas/user_schemas.py: -------------------------------------------------------------------------------- 1 | __all__ = ["UserSchema", "UserPatchSchema"] 2 | 3 | from marshmallow.fields import Pluck, Str 4 | 5 | from .base_schemas import AuditEntitySchemaMixin, BaseEntitySchema 6 | from .company_schemas import CompanySchema 7 | 8 | 9 | class UserSchema(BaseEntitySchema, AuditEntitySchemaMixin): 10 | primary_company = Pluck(CompanySchema, "id", dump_only=True) 11 | name = Str(required=True) 12 | email = Str(required=True) 13 | username = Str(required=False) 14 | 15 | 16 | class UserPatchSchema(UserSchema): 17 | class Meta: 18 | # excluded email and foreign_user_id; cannot be changed after creation! 19 | fields = ("name", "admin", "active") 20 | -------------------------------------------------------------------------------- /observability_api/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_api/tests/__init__.py -------------------------------------------------------------------------------- /observability_api/tests/functional/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_api/tests/functional/__init__.py -------------------------------------------------------------------------------- /observability_api/tests/integration/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_api/tests/integration/__init__.py -------------------------------------------------------------------------------- /observability_api/tests/integration/helpers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_api/tests/integration/helpers/__init__.py -------------------------------------------------------------------------------- /observability_api/tests/integration/schemas/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_api/tests/integration/schemas/__init__.py -------------------------------------------------------------------------------- /observability_api/tests/integration/schemas/conftest.py: -------------------------------------------------------------------------------- 1 | from testlib.fixtures.entities import * 2 | -------------------------------------------------------------------------------- /observability_api/tests/integration/v1_endpoints/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_api/tests/integration/v1_endpoints/__init__.py -------------------------------------------------------------------------------- /observability_api/tests/integration/v1_endpoints/test_converters.py: -------------------------------------------------------------------------------- 1 | from http import HTTPStatus 2 | 3 | import pytest 4 | 5 | from common.entities import Company, Organization, Project 6 | 7 | 8 | @pytest.mark.integration 9 | def test_32_uuid_converter(client, g_user_2_admin): 10 | # We have a converter which allows us to reference UUIDs by their dashless version 11 | company = Company.create(name="Foo") 12 | org = Organization.create(name="Foo", company=company) 13 | proj = Project.create(name="Foo", active=True, organization=org) 14 | response = client.get(f"/observability/v1/projects/{str(proj.id).replace('-', '')}") 15 | assert response.status_code == HTTPStatus.OK, response.json 16 | assert response.json["id"] == str(proj.id) 17 | -------------------------------------------------------------------------------- /observability_api/tests/unit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_api/tests/unit/__init__.py -------------------------------------------------------------------------------- /observability_api/tests/unit/helpers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_api/tests/unit/helpers/__init__.py -------------------------------------------------------------------------------- /observability_api/tests/unit/schemas/test_testgen_test_outcome_integration_schemas.py: -------------------------------------------------------------------------------- 1 | from decimal import Decimal 2 | 3 | import pytest 4 | 5 | from observability_api.schemas import TestgenItemTestParametersSchema 6 | 7 | 8 | @pytest.mark.unit 9 | def test_testgen_item_parameters_dump(): 10 | data = TestgenItemTestParametersSchema().dump({"name": "my-attr", "value": Decimal("10.0")}) 11 | expected = {"value": "10.0", "name": "my-attr"} 12 | assert expected == data 13 | -------------------------------------------------------------------------------- /observability_api/tests/unit/v1_endpoints/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_api/tests/unit/v1_endpoints/__init__.py -------------------------------------------------------------------------------- /observability_ui/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | 15 | [*.ts] 16 | ij_typescript_imports_wrap = off 17 | ij_typescript_enforce_trailing_comma = keep 18 | # ij_typescript_spaces_within_array_initializer_brackets = true 19 | -------------------------------------------------------------------------------- /observability_ui/.prettierignore: -------------------------------------------------------------------------------- 1 | # Add files here to ignore them from prettier formatting 2 | 3 | /dist 4 | /coverage 5 | 6 | .angular 7 | -------------------------------------------------------------------------------- /observability_ui/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /observability_ui/.yarnrc: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | yarn-path ".yarn/releases/yarn-1.22.21.cjs" 6 | -------------------------------------------------------------------------------- /observability_ui/apps/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_ui/apps/.gitkeep -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/module-federation.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'basic-auth', 3 | exposes: { 4 | './Authentication': 'apps/basic-auth/src/app/authentication/authentication.module.ts', 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@observability/basic-auth", 3 | "version": "2.0.0", 4 | "description": "adds support for username/password authentication to the host app" 5 | } 6 | -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'auth-root', 5 | template: '' 6 | 7 | }) 8 | export class AppComponent {} -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { RouterModule } from '@angular/router'; 4 | import { AppComponent } from './app.component'; 5 | 6 | @NgModule({ 7 | declarations: [AppComponent], 8 | imports: [ 9 | BrowserModule, 10 | RouterModule.forRoot([ 11 | { 12 | path: '', 13 | loadChildren: () => import('./authentication/authentication.module').then(m => m.AuthenticationModule) 14 | } 15 | ], { initialNavigation: 'enabledBlocking' }), 16 | ], 17 | providers: [], 18 | bootstrap: [AppComponent], 19 | }) 20 | export class AppModule {} 21 | -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/src/app/app.routes.ts: -------------------------------------------------------------------------------- 1 | import { Route } from '@angular/router'; 2 | 3 | export const appRoutes: Route[] = [ 4 | {path: '', loadChildren: () => import('./authentication/authentication.module').then(m => m.AuthenticationModule)}, 5 | ]; 6 | -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/src/app/authentication/authentication.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'auth-entry', 5 | template: ``, 6 | styles: [` 7 | :host { 8 | width: 100%; 9 | height: 100%; 10 | } 11 | `], 12 | }) 13 | export class AuthenticationComponent {} 14 | -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/src/app/authentication/authentication.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { RouterModule } from '@angular/router'; 4 | 5 | import { AuthenticationComponent } from './authentication.component'; 6 | import { remoteRoutes } from './authentication.routes'; 7 | 8 | @NgModule({ 9 | declarations: [ 10 | AuthenticationComponent 11 | ], 12 | imports: [ 13 | CommonModule, 14 | RouterModule.forChild(remoteRoutes), 15 | ], 16 | providers: [], 17 | }) 18 | export class AuthenticationModule {} 19 | -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/src/app/logout/logout.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | Documentation Library 4 |
5 | 6 | 7 |
8 |

You have logged out of Observability

9 | 10 |
11 | 13 | Back to Login 14 | 15 |
16 |
17 | -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_ui/apps/basic-auth/src/assets/.gitkeep -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/src/bootstrap.ts: -------------------------------------------------------------------------------- 1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 2 | import { AppModule } from './app/app.module'; 3 | 4 | platformBrowserDynamic() 5 | .bootstrapModule(AppModule) 6 | .catch((err) => console.error(err)); 7 | -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_ui/apps/basic-auth/src/favicon.ico -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | basic-auth 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/src/main.ts: -------------------------------------------------------------------------------- 1 | import('./bootstrap').catch(err => console.error(err)); 2 | -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": [], 6 | "target": "ES2022" 7 | }, 8 | "files": [ 9 | "src/main.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.d.ts" 13 | ], 14 | "exclude": [ 15 | "jest.config.ts", 16 | "src/**/*.test.ts", 17 | "src/**/*.spec.ts" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/tsconfig.editor.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": [ 4 | "src/**/*.ts" 5 | ], 6 | "compilerOptions": { 7 | "types": [ 8 | "jest", 9 | "node" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "target": "es2016", 7 | "types": ["jest", "node"], 8 | "noImplicitAny": false, 9 | }, 10 | "files": ["src/test-setup.ts"], 11 | "include": [ 12 | "jest.config.ts", 13 | "src/**/*.test.ts", 14 | "src/**/*.spec.ts", 15 | "src/**/*.d.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/webpack.config.js: -------------------------------------------------------------------------------- 1 | const { CreateConfig } = require('../../libs/webpack-config'); 2 | const moduleFedarationConfig = require('./module-federation.config'); 3 | 4 | module.exports = CreateConfig(moduleFedarationConfig); 5 | -------------------------------------------------------------------------------- /observability_ui/apps/basic-auth/webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./webpack.config'); 2 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/module-federation.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'shell', 3 | remotes: [] 4 | }; 5 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@observability/shell", 3 | "version": "2.0.0", 4 | "description": "this is the shell app of observability mfe setup", 5 | "license": "MIT" 6 | } 7 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/app-version/app-version.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_ui/apps/shell/src/app/app-version/app-version.component.css -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/app-version/app-version.component.html: -------------------------------------------------------------------------------- 1 |

There is a new version available.

2 |
{{newVersion$ | async | json}}
3 | Please reload the page to run the new version! 4 | or 5 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/app-version/app-version.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { AppVersionService } from './app-version.service'; 3 | 4 | @Component({ 5 | selector: 'shell-app-version', 6 | templateUrl: './app-version.component.html', 7 | styleUrls: [ './app-version.component.css' ] 8 | }) 9 | export class AppVersionComponent { 10 | 11 | newVersion$ = this.appVersion.nextVersion$; 12 | 13 | constructor( 14 | private appVersion: AppVersionService, 15 | ) {} 16 | 17 | reloadPage() { 18 | window.location.reload(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | @use '@angular/material' as mat; 2 | 3 | .container { 4 | display: flex; 5 | flex-direction: column; 6 | position: absolute; 7 | top: 0; 8 | bottom: 0; 9 | left: 0; 10 | right: 0; 11 | } 12 | 13 | .sidenav-container { 14 | flex: 1; 15 | 16 | &--menu { 17 | @include mat.elevation(8); 18 | 19 | width: 200px; 20 | } 21 | } 22 | 23 | .main-content { 24 | display: flex; 25 | flex-direction: column; 26 | height: 100%; 27 | overflow: hidden; 28 | } 29 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/components/default-error-handler/default-error.handler.ts: -------------------------------------------------------------------------------- 1 | import { ErrorHandler, Injectable } from '@angular/core'; 2 | import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar'; 3 | import { DefaultErrorHandlerComponent } from './default-error-handler.component'; 4 | 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class DefaultErrorHandler extends ErrorHandler { 10 | 11 | constructor( 12 | private snackbar: MatSnackBar, 13 | ) { 14 | super(); 15 | } 16 | 17 | override handleError(error: any) { 18 | super.handleError(error); 19 | this.snackbar.openFromComponent(DefaultErrorHandlerComponent, {duration: 3000, data: error, }); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/components/email-action/email-action.component.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/mixins' as mixins; 2 | @use '@observability/ui/styles/variables' as variables; 3 | 4 | :host { 5 | display: flex; 6 | flex-direction: column; 7 | width: 100%; 8 | } 9 | 10 | .not-configured { 11 | padding: 8px 0; 12 | } 13 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/components/offline/offline.component.html: -------------------------------------------------------------------------------- 1 |

offline works!

2 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/components/offline/offline.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_ui/apps/shell/src/app/components/offline/offline.component.scss -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/components/offline/offline.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'shell-offline', 5 | templateUrl: './offline.component.html', 6 | styleUrls: [ './offline.component.scss' ] 7 | }) 8 | export class OfflineComponent { 9 | } 10 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/components/rules-actions/action/action-template.component.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/variables' as vars; 2 | 3 | mat-panel-title { 4 | min-width: 80px; 5 | } 6 | 7 | mat-expansion-panel { 8 | border: vars.$border; 9 | } 10 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/components/rules-actions/alert/templating-alert.component.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/mixins' as mixins; 2 | @use '@observability/ui/styles/variables' as variables; 3 | 4 | :host { 5 | @include mixins.flex-row(); 6 | 7 | * { 8 | font-size: 14px; 9 | color: variables.$dark-accent-text; 10 | font-weight: normal; 11 | } 12 | 13 | mat-icon { 14 | @include mixins.icon-size(16px) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/components/rules-actions/implementations/rules/example/example-rule-label.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | // eslint-disable-next-line @angular-eslint/component-selector 5 | selector: 'label-example-rule', 6 | template: `🌈 example rule label 🦄`, 7 | standalone: true, 8 | styles: [ ` 9 | .label { 10 | text-transform: capitalize; 11 | } 12 | ` ], 13 | }) 14 | export class ExampleRuleLabelComponent { 15 | } 16 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/components/rules-actions/implementations/rules/run-state/run-state-rule.component.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/mixins' as mixins; 2 | 3 | :host { 4 | display: flex; 5 | flex-direction: row; 6 | } 7 | 8 | .count-input { 9 | width: 32px; 10 | } 11 | 12 | .advanced-options-link-container { 13 | display: flex; 14 | width: 100%; 15 | margin-top: 16px; 16 | font-size: 12px; 17 | 18 | .advanced-options-link { 19 | @include mixins.link(); 20 | @include mixins.link-with-icon(); 21 | @include mixins.flex-row(); 22 | 23 | mat-icon { 24 | @include mixins.icon-size(14px); 25 | margin-left: 2px; 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/components/rules-actions/rule.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { EntityService, EntityType } from '@observability-ui/core'; 3 | import { Rule } from './rule.model'; 4 | 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class RuleService extends EntityService { 10 | protected override baseEntity: EntityType = EntityType.Rule; 11 | protected override parentEntity = EntityType.Journey; 12 | } 13 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/components/sidenav-menu/sidenav-menu.model.ts: -------------------------------------------------------------------------------- 1 | import { ComponentType } from '@angular/cdk/overlay'; 2 | 3 | export interface Menu { 4 | label: string; 5 | items: (MenuItemLink|MenuItemComponent)[]; 6 | } 7 | 8 | export interface MenuItemLink { 9 | icon: string; 10 | label: string; 11 | link: any[]; 12 | } 13 | 14 | export interface MenuItemComponent { 15 | component: ComponentType 16 | } 17 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/components/summary-item/summary-item.component.html: -------------------------------------------------------------------------------- 1 |
3 |
{{label}}
4 |
{{count}}
5 |
6 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/components/summary-item/summary-item.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | import { NgClass, NgStyle } from '@angular/common'; 3 | 4 | @Component({ 5 | selector: 'shell-summary-item', 6 | templateUrl: 'summary-item.component.html', 7 | styleUrls: [ 'summary-item.component.scss' ], 8 | imports: [ 9 | NgStyle, 10 | NgClass 11 | ], 12 | standalone: true 13 | }) 14 | 15 | export class SummaryItemComponent { 16 | @Input() count: number; 17 | @Input() color: string; 18 | @Input() label: string; 19 | } 20 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/components/summary/summary.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
6 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/components/summary/summary.component.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/mixins' as mixins; 2 | 3 | :host { 4 | width: 100%; 5 | } 6 | 7 | .items-container { 8 | @include mixins.flex-row($justify: flex-start); 9 | } 10 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/components/summary/summary.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { SummaryComponent } from './summary.component'; 3 | 4 | describe('summary', () => { 5 | let component: SummaryComponent; 6 | let fixture: ComponentFixture; 7 | 8 | beforeEach(async () => { 9 | await TestBed.configureTestingModule({ 10 | imports: [ SummaryComponent, ], 11 | }).compileComponents(); 12 | 13 | fixture = TestBed.createComponent(SummaryComponent); 14 | component = fixture.componentInstance; 15 | 16 | fixture.detectChanges(); 17 | }); 18 | 19 | it('should create', () => { 20 | expect(component).toBeTruthy(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/guards/is-online.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Router, UrlTree } from '@angular/router'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class IsOnlineGuard { 8 | constructor(private router: Router) {} 9 | 10 | canActivate(): boolean | UrlTree { 11 | return navigator.onLine || this.router.parseUrl('/offline'); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/api-keys/api-keys.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { EntityService, EntityType, ServiceKey } from '@observability-ui/core'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class APIKeysService extends EntityService { 8 | 9 | protected override parentEntity = EntityType.Project; 10 | protected override baseEntity = EntityType.ServiceKey; 11 | } 12 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/api-keys/api-keys.store.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { APIKeysStore } from './api-keys.store'; 3 | import { MockProvider } from '@datakitchen/ngx-toolkit'; 4 | import { APIKeysService } from './api-keys.service'; 5 | 6 | describe('api-keys.store', () => { 7 | 8 | let store: APIKeysStore; 9 | 10 | beforeEach(async () => { 11 | await TestBed.configureTestingModule({ 12 | 13 | providers: [ 14 | APIKeysStore, 15 | MockProvider(APIKeysService) 16 | ], 17 | }); 18 | 19 | store = TestBed.inject(APIKeysStore); 20 | 21 | }); 22 | 23 | it('should create', () => { 24 | expect(store).toBeTruthy(); 25 | }); 26 | 27 | }); 28 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/components/add-component-dialog/add-component-dialog.component.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/variables' as variables; 2 | @use '@observability/ui/styles/mixins' as mixins; 3 | 4 | mat-form-field { 5 | width: 100%; 6 | } 7 | 8 | textarea { 9 | resize: none; 10 | width: 100%; 11 | } 12 | 13 | .top-margin { 14 | margin-top: 8px 15 | } 16 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/components/add-component-dialog/add-component-dialog.translation.ts: -------------------------------------------------------------------------------- 1 | export const addComponentDialogTranslation = { 2 | addComponentDialog: { 3 | title: 'Add Component', 4 | required: 'Field is required', 5 | existing: 'Key already in use', 6 | componentType: 'Component Type', 7 | cancel: 'Cancel', 8 | adding: 'Adding', 9 | add: 'Add' 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/components/components-list/component-list.translation.ts: -------------------------------------------------------------------------------- 1 | export const componentListTranslation = { 2 | key: 'Key', 3 | addComponent: 'Add Component', 4 | noComponents: 'No components found.', 5 | componentTypes: 'Component Types', 6 | allComponentTypes: 'All Component Types', 7 | emptyComponentsList: { 8 | title: 'No components? Begin by connecting your Data Estate', 9 | description: 'Integrate your tools so the system can create components when it receives events', 10 | button: 'Go to Integrations', 11 | learnMore: 'Get started with Observability' 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/components/components-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule } from '@angular/router'; 3 | import { ComponentsListComponent } from './components-list/components-list.component'; 4 | 5 | @NgModule({ 6 | imports: [ 7 | RouterModule.forChild([ 8 | { 9 | path: '', 10 | component: ComponentsListComponent, 11 | data: { 12 | helpLink: 'article/dataops-observability-help/components' 13 | }, 14 | }, 15 | ]), 16 | 17 | ], 18 | exports: [ RouterModule ], 19 | }) 20 | export class ComponentsRoutingModule { 21 | } 22 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/events/batch-runs/batch-runs.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: flex; 3 | flex-direction: column; 4 | flex-grow: 1; 5 | } 6 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/events/event-list/event-list.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: flex; 3 | flex-direction: column; 4 | flex-grow: 1; 5 | } 6 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/events/events.component.html: -------------------------------------------------------------------------------- 1 |
2 |

{{'events' | translate | titlecase}}

3 |
4 | 5 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/events/events.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: flex; 3 | flex-direction: column; 4 | height: 100%; 5 | width: 100%; 6 | } 7 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/events/events.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { CoreComponent } from '@datakitchen/ngx-toolkit'; 3 | 4 | @Component({ 5 | selector: 'shell-events', 6 | templateUrl: 'events.component.html', 7 | styleUrls: [ 'events.component.scss' ], 8 | }) 9 | export class EventsComponent extends CoreComponent { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/instances/instance-events/instance-events.component.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/mixins' as mixins; 2 | @use '@observability/ui/styles/variables' as variables; 3 | 4 | :host { 5 | @include mixins.flex-column($justify: flex-start, $align: stretch); 6 | 7 | flex: 1; 8 | } 9 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/instances/instance-runs/instance-runs.component.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/mixins' as mixins; 2 | @use '@observability/ui/styles/variables' as variables; 3 | 4 | :host { 5 | @include mixins.flex-column($justify: flex-start, $align: stretch); 6 | flex: 1; 7 | } 8 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/integrations/integrations.model.ts: -------------------------------------------------------------------------------- 1 | import { InjectionToken } from '@angular/core'; 2 | import { AbstractTool } from './tools/abstract-tool.directive'; 3 | 4 | export type ToolIcon = {_name: string; _displayName: string; _icon: string}; 5 | 6 | export const INTEGRATION_TOOLS = new InjectionToken('INTEGRATION_TOOLS', { 7 | providedIn: 'root', 8 | factory: () => [] 9 | }); 10 | 11 | export const EXTRA_TOOL_ICONS = new InjectionToken('EXTRA_TOOL_ICONS', { 12 | providedIn: 'root', 13 | factory: () => [] 14 | }); 15 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/integrations/integrations.translations.ts: -------------------------------------------------------------------------------- 1 | export const integrationsTranslations = { 2 | noIntegrations: 'No integrations found.', 3 | integrations: 'Integrations', 4 | setup: { 5 | title: 'Connect to your Data Estate', 6 | subtitle: 'Configure agents to integrate your tools and send events to DataOps Observability', 7 | learnMoreAbout: 'Learn more about' 8 | }, 9 | availableIntegrations: 'View Available Agents', 10 | searchIntegrations: 'Search Integrations', 11 | alert: 'Don’t see the integration you need? Build your own using our', 12 | alertLink: 'agent framework' 13 | }; 14 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/journeys/journey-details/journey-details.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | height: 100%; 3 | display: flex; 4 | flex-direction: column; 5 | } 6 | 7 | nav { 8 | .link { 9 | opacity: 1 !important; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/journeys/journey-rules/journey-rules.component.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/variables' as vars; 2 | @use '@observability/ui/styles/mixins' as mixins; 3 | 4 | mat-progress-spinner { 5 | margin: auto; 6 | } 7 | 8 | .rule { 9 | padding: vars.$space-xs vars.$space-xs; 10 | border: vars.$border; 11 | background: vars.$white; 12 | border: vars.$border; 13 | margin-top: vars.$space-xs; 14 | 15 | &:last-child { 16 | margin-bottom: vars.$space-md; 17 | } 18 | } 19 | 20 | .action { 21 | padding: vars.$space-xs; 22 | } 23 | 24 | :host ::ng-deep .add-rule-button span { 25 | @include mixins.flex-row(); 26 | 27 | mat-icon { 28 | margin-right: 4px; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/journeys/no-components-dialog/no-components-dialog.component.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/variables' as variables; 2 | 3 | .no-components-setup { 4 | border: none; 5 | padding: 0; 6 | height: auto; 7 | 8 | .title { 9 | font-size: 18px; 10 | margin-top: variables.$space-sm; 11 | } 12 | } 13 | 14 | .body { 15 | text-align: center; 16 | margin-top: variables.$space-sm; 17 | } 18 | 19 | .add-button { 20 | margin-top: variables.$space-lg; 21 | margin-bottom: variables.$space-lg; 22 | } 23 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/project-display/project-display.component.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/mixins' as mixins; 2 | @use '@observability/ui/styles/variables' as variables; 3 | 4 | .project-container { 5 | margin-left: variables.$space-md; 6 | margin-bottom: variables.$space-sm; 7 | margin-top: variables.$space-xs; 8 | 9 | .project-label { 10 | @include mixins.font-style($style: caption, $color: secondary); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/runs-table/runs-table.module.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_ui/apps/shell/src/app/projects/runs-table/runs-table.module.ts -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/runs/run-events/run-events.component.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/mixins' as mixins; 2 | @use '@observability/ui/styles/variables' as variables; 3 | 4 | :host { 5 | @include mixins.flex-column($justify: flex-start, $align: stretch); 6 | 7 | flex: 1; 8 | } 9 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/runs/run-timeline/run-timeline.component.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/mixins' as mixins; 2 | @use '@observability/ui/styles/variables' as variables; 3 | 4 | :host { 5 | display: flex; 6 | flex-direction: column; 7 | height: 100%; 8 | width: 100%; 9 | } 10 | 11 | mat-card { 12 | height: 100%; 13 | } 14 | 15 | gantt-chart { 16 | max-height: 100%; 17 | } 18 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/runs/runs-table/run-states/run-states.component.html: -------------------------------------------------------------------------------- 1 |
2 | {{'runStatus.' + state | translate}} 3 | warning_amber 4 |
5 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/runs/runs-table/run-time/run-time.component.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/mixins' as mixins; 2 | @use '@observability/ui/styles/variables' as variables; 3 | 4 | small { 5 | font-size: 10px; 6 | @include mixins.font-color(disabled); 7 | } 8 | 9 | mat-icon { 10 | @include mixins.icon-size(16px); 11 | 12 | color: variables.$red-500; 13 | } 14 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/runs/runs.translation.ts: -------------------------------------------------------------------------------- 1 | import { MessageLogLevel } from '@observability-ui/core'; 2 | 3 | export const runsTranslation = { 4 | allTasks: 'All Tasks', 5 | noSelectedTask: 'Tasks', 6 | 7 | backToRuns: 'Back to Batch Runs', 8 | component_id: 'Component ID', 9 | 10 | graph: { 11 | errors: { 12 | renderingError: 'Unable to render the graph', 13 | action: 'Refresh', 14 | }, 15 | }, 16 | events: { 17 | logLevels: { 18 | [MessageLogLevel.Error]: 'Error', 19 | [MessageLogLevel.Warning]: 'Warning', 20 | [MessageLogLevel.Info]: 'Info', 21 | }, 22 | }, 23 | taskKey: 'Task Key', 24 | observedGraph: 'Observed Graph' 25 | }; 26 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/settings/settings.component.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/mixins' as mixins; 2 | @use '@observability/ui/styles/variables' as variables; 3 | 4 | :host { 5 | display: flex; 6 | flex-direction: column; 7 | height: 100%; 8 | width: 100%; 9 | } 10 | 11 | mat-form-field { 12 | width: 100%; 13 | } 14 | 15 | .scrolling-content { 16 | max-width: 700px; 17 | } 18 | 19 | .bottom-chip { 20 | font-size: 12px; 21 | color: variables.$gray-700; 22 | border: 2px solid variables.$gray-200; 23 | padding: variables.$space-xxs variables.$space-xs; 24 | border-radius: 2px; 25 | background: variables.$gray-100; 26 | } 27 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/projects/task-test-summary/task-test-summary.utils.ts: -------------------------------------------------------------------------------- 1 | type AggregatedSummary = { 2 | [status in T['status']]?: number; 3 | } & { TOTAL: number }; 4 | 5 | export function getCompleteSummary(summaries: T[] = []): AggregatedSummary { 9 | const aggregate: AggregatedSummary = { TOTAL: 0 }; 10 | for (const item of summaries) { 11 | aggregate[item.status as T['status']] = (aggregate[item.status as T['status']] ?? 0) + (item.count ?? 1) as any; 12 | aggregate.TOTAL += item.count; 13 | } 14 | 15 | return aggregate; 16 | } 17 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/services/project-runs/project-runs.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { EntityService, EntityType, Run } from '@observability-ui/core'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class ProjectRunsService extends EntityService { 8 | protected override parentEntity = EntityType.Project; 9 | protected override baseEntity = EntityType.Run; 10 | } 11 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/services/run-events/run-events.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { EntityService, EntityType, EventType } from '@observability-ui/core'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class RunEventsService extends EntityService { 8 | 9 | protected override parentEntity = EntityType.Run; 10 | protected override baseEntity = EntityType.Event; 11 | } 12 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/stores/run-events/run-events.store.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { EntityActions, EntityState, EntityStore, EventType } from '@observability-ui/core'; 3 | import { RunEventsService } from '../../services/run-events/run-events.service'; 4 | import { makeStore } from '@microphi/store'; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class RunEventsStore extends EntityStore, EntityActions> implements makeStore, EntityActions> { 10 | constructor(protected service: RunEventsService) { 11 | super({ 12 | list: [], 13 | total: 0, 14 | }); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/app/stores/run-tasks/run-tasks.store.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { EntityActions, EntityState, EntityStore, RunTask } from '@observability-ui/core'; 3 | import { RunTasksService } from '../../services/run-tasks/run-tasks.service'; 4 | import { makeStore } from '@microphi/store'; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | /** 10 | * TODO this should be under the RunStore 11 | */ 12 | export class RunTasksStore extends EntityStore, EntityActions> implements makeStore, EntityActions> { 13 | 14 | constructor(protected service: RunTasksService) { 15 | super({ 16 | total: 0, 17 | list: [] 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_ui/apps/shell/src/assets/.gitkeep -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/assets/databricks.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/assets/dataset.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/assets/icons/icon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_ui/apps/shell/src/assets/icons/icon-128x128.png -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/assets/icons/icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_ui/apps/shell/src/assets/icons/icon-144x144.png -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/assets/icons/icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_ui/apps/shell/src/assets/icons/icon-152x152.png -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/assets/icons/icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_ui/apps/shell/src/assets/icons/icon-192x192.png -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/assets/icons/icon-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_ui/apps/shell/src/assets/icons/icon-384x384.png -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/assets/icons/icon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_ui/apps/shell/src/assets/icons/icon-512x512.png -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/assets/icons/icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_ui/apps/shell/src/assets/icons/icon-72x72.png -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/assets/icons/icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_ui/apps/shell/src/assets/icons/icon-96x96.png -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/assets/module-federation.manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "basic-auth": { 3 | "routePath": "authentication", 4 | "remoteEntry": "http://localhost:4201/remoteEntry.js", 5 | "remoteName": "basic-auth", 6 | "exposedModule": "./Authentication", 7 | "exposedModuleName": "AuthenticationModule" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/assets/server.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.tpl" { 2 | const value: string; 3 | export default value; 4 | } -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/environments/environment.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiBaseUrl": "/api" 3 | } 4 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | }; 4 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_ui/apps/shell/src/favicon.ico -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/main.ts: -------------------------------------------------------------------------------- 1 | import('./bootstrap').catch((err) => console.error(err)); 2 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/module-federation.manifest.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "basic-auth": { 3 | "routePath": "authentication", 4 | "remoteEntry": "/auth/remoteEntry.js", 5 | "remoteName": "basic-auth", 6 | "exposedModule": "./Authentication", 7 | "exposedModuleName": "AuthenticationModule" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | 3 | class ResizeObserver { 4 | // eslint-disable-next-line @typescript-eslint/no-empty-function 5 | observe() {} 6 | // eslint-disable-next-line @typescript-eslint/no-empty-function 7 | unobserve() {} 8 | // eslint-disable-next-line @typescript-eslint/no-empty-function 9 | disconnect() {} 10 | } 11 | 12 | window.ResizeObserver = ResizeObserver; 13 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": [], 6 | "target": "ES2022", 7 | "useDefineForClassFields": false 8 | }, 9 | "files": ["src/main.ts", "src/polyfills.ts"], 10 | "include": ["src/**/*.d.ts"], 11 | "exclude": ["**/*.test.ts", "**/*.spec.ts", "jest.config.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/tsconfig.editor.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["**/*.ts"], 4 | "compilerOptions": { 5 | "types": ["jest", "node"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"], 7 | "target": "es2016", 8 | "noImplicitAny": false, 9 | }, 10 | "files": ["src/test-setup.ts"], 11 | "include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts", "jest.config.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/webpack.config.js: -------------------------------------------------------------------------------- 1 | const { CreateConfig } = require("../../libs/webpack-config"); 2 | const moduleFedarationConfig = require('./module-federation.config'); 3 | 4 | module.exports = CreateConfig(moduleFedarationConfig); 5 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/webpack.dev.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./webpack.config'); 2 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./webpack.dev.config'); 2 | -------------------------------------------------------------------------------- /observability_ui/apps/shell/webpack.staging.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./webpack.dev.config'); 2 | -------------------------------------------------------------------------------- /observability_ui/jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require('@nx/jest/preset').default; 2 | 3 | module.exports = { 4 | ...nxPreset, 5 | }; 6 | -------------------------------------------------------------------------------- /observability_ui/lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "apps/*", 4 | "libs/*" 5 | ], 6 | "npmClient": "yarn", 7 | "version": "2.0.0", 8 | "granularPathspec": false, 9 | "command": {} 10 | } 11 | -------------------------------------------------------------------------------- /observability_ui/libs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/observability_ui/libs/.gitkeep -------------------------------------------------------------------------------- /observability_ui/libs/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@observability/core", 3 | "version": "2.0.0", 4 | "description": "this is the core lib of observability mfe setup", 5 | "license": "MIT" 6 | } 7 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/actions/actions.model.ts: -------------------------------------------------------------------------------- 1 | import { InjectionToken } from '@angular/core'; 2 | import { RunProcessedStatus } from '../models'; 3 | import { AbstractAction } from './abstract-action/abstract-action.directive'; 4 | 5 | export const TaskStatusEmailTemplate = { 6 | [RunProcessedStatus.Running]: 'task_status_started', 7 | [RunProcessedStatus.Completed]: 'task_status_completed', 8 | [RunProcessedStatus.CompletedWithWarnings]: 'task_status_warning', 9 | [RunProcessedStatus.Failed]: 'task_status_error', 10 | }; 11 | 12 | export const RULE_ACTIONS = new InjectionToken('RULE_ACTIONS'); 13 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/actions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './actions.model'; 2 | export * from './abstract-action/abstract-action.directive'; 3 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/config/app-configuration.ts: -------------------------------------------------------------------------------- 1 | export interface AppConfiguration { 2 | apiBaseUrl: string; 3 | } 4 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/config/index.ts: -------------------------------------------------------------------------------- 1 | export * from './app-configuration'; 2 | export * from './config.service'; 3 | export * from './provide-from-config'; 4 | 5 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/config/provide-from-config.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | import { ConfigService } from './config.service'; 3 | import { filter, map, take } from 'rxjs'; 4 | import { AppConfiguration } from './app-configuration'; 5 | 6 | export function ProvideFromConfig(provide: any, key: keyof AppConfiguration, mapFn: (value: any) => any = (v) => v) { 7 | return { 8 | provide: provide, 9 | useFactory: (config: ConfigService) => { 10 | return config.ready$.pipe( 11 | filter((ready) => ready), 12 | map(() => { 13 | return config.get(key); 14 | }), 15 | map((value) => mapFn(value)), 16 | take(1), 17 | ); 18 | 19 | }, 20 | deps: [ ConfigService ] 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/decorators/index.ts: -------------------------------------------------------------------------------- 1 | export * from './host-resize/host-resize'; 2 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/entities/agent/agent.model.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '../../entity'; 2 | 3 | export interface Agent extends Entity { 4 | key: string; 5 | tool: string; 6 | version: string; 7 | status: AgentStatus; 8 | latest_heartbeat: string; 9 | latest_event_timestamp?: string; 10 | } 11 | 12 | export enum AgentStatus { 13 | Online = 'ONLINE', 14 | Unhealthy = 'UNHEALTHY', 15 | Offline = 'OFFLINE', 16 | } 17 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/entities/agent/service/agent.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { EntityService, EntityType } from '../../../entity'; 3 | import { Agent } from '../agent.model'; 4 | 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class AgentService extends EntityService{ 10 | protected readonly baseEntity = EntityType.Agent; 11 | protected override readonly parentEntity = EntityType.Project; 12 | } 13 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/entities/agent/store/agent.actions.ts: -------------------------------------------------------------------------------- 1 | import { EntityActions } from '../../../entity'; 2 | import { Agent } from '../agent.model'; 3 | 4 | export interface AgentActions extends EntityActions { 5 | } 6 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/entities/agent/store/agent.state.ts: -------------------------------------------------------------------------------- 1 | import { EntityState } from '../../../entity'; 2 | import { Agent } from '../agent.model'; 3 | 4 | export interface AgentState extends EntityState { 5 | } 6 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/entities/agent/store/agent.store.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { AgentService, AgentStore } from '../../'; 3 | import { MockProvider } from '@datakitchen/ngx-toolkit'; 4 | 5 | describe('agent.store', () => { 6 | 7 | let store: AgentStore; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | providers: [ 12 | AgentStore, 13 | MockProvider(AgentService) 14 | ], 15 | }); 16 | 17 | store = TestBed.inject(AgentStore); 18 | 19 | }); 20 | 21 | it('should create', () => { 22 | expect(store).toBeTruthy(); 23 | }); 24 | 25 | }); 26 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/entities/agent/store/agent.store.ts: -------------------------------------------------------------------------------- 1 | import { makeStore } from '@microphi/store'; 2 | import { EntityStore } from '../../../entity'; 3 | import { Agent } from '../agent.model'; 4 | import { AgentService } from '../service/agent.service'; 5 | import { AgentState } from './agent.state'; 6 | import { AgentActions } from './agent.actions'; 7 | import { Injectable } from '@angular/core'; 8 | 9 | @Injectable({ 10 | providedIn: 'root' 11 | }) 12 | export class AgentStore extends EntityStore implements makeStore { 13 | 14 | constructor(protected service: AgentService) { 15 | super({ 16 | list: [], 17 | total: 0, 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/entities/index.ts: -------------------------------------------------------------------------------- 1 | export * from './agent/agent.model'; 2 | export * from './agent/service/agent.service'; 3 | export * from './agent/store/agent.actions'; 4 | export * from './agent/store/agent.state'; 5 | export * from './agent/store/agent.store'; 6 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/entity/entity-type.ts: -------------------------------------------------------------------------------- 1 | export enum EntityType { 2 | User = 'User', 3 | Company = 'Company', 4 | Organization = 'Organization', 5 | Project = 'Project', 6 | Event = 'Event', 7 | Run = 'Run', 8 | Pipeline = 'Pipeline', 9 | Task = 'Task', 10 | Rule = 'Rule', 11 | Journey = 'Journey', 12 | Instance = 'Instance', 13 | Component = 'Component', 14 | ServiceKey = 'ServiceAccountKey', 15 | Dashboards = 'Dashboards', 16 | Agent = 'Agent', 17 | ProjectAlertSettings = 'ProjectAlertSettings', 18 | } 19 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/entity/index.ts: -------------------------------------------------------------------------------- 1 | 2 | export * from './entity.service'; 3 | export * from './entity.store'; 4 | export * from './entity.model'; 5 | export * from './read-only-rest-api.service'; 6 | export { EntityType } from './entity-type'; 7 | export { entityDefaultUrlMappings } from './entity-default-url.mappings'; 8 | 9 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/guards/no-auth/no-auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { UrlTree } from '@angular/router'; 3 | import { map } from 'rxjs/operators'; 4 | import { Observable } from 'rxjs'; 5 | import { SessionService } from '../../services/auth/session.service'; 6 | 7 | @Injectable({ providedIn: 'root' }) 8 | export class NoAuthGuard { 9 | constructor(private sessionService: SessionService) {} 10 | 11 | canActivate(): Observable { 12 | return this.sessionService.isLoggedIn$.pipe( 13 | map((isLoggedIn) => !isLoggedIn), 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/guards/reset-stores.guard.ts: -------------------------------------------------------------------------------- 1 | import { CanActivateFn } from "@angular/router"; 2 | import { EntityStore } from "../entity"; 3 | import { inject } from "@angular/core"; 4 | 5 | export function resetStores(...stores: Array>): CanActivateFn { 6 | return () => { 7 | for (const storeType of stores) { 8 | inject(storeType).dispatch('reset'); 9 | } 10 | return true; 11 | }; 12 | } -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/interceptors/index.ts: -------------------------------------------------------------------------------- 1 | export * from './base-http.interceptor'; 2 | export * from './filter-params.interceptor'; 3 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/models/alert.model.ts: -------------------------------------------------------------------------------- 1 | export interface Alert { 2 | /** 3 | * Where `Type` must be an enum with possible types such as 4 | * 5 | * export enum AlertType { 6 | * lateStart = 'LATE_START', 7 | * lateEnd = 'LATE_END', 8 | * } 9 | */ 10 | 11 | id: string; 12 | run: string; 13 | level: AlertLevel; 14 | type: AlertType; 15 | name?: string; 16 | description: string; 17 | created_on: string; 18 | } 19 | 20 | export type AlertLevel = 'WARNING' | 'ERROR'; 21 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/models/index.ts: -------------------------------------------------------------------------------- 1 | export * from './alert.model'; 2 | export * from './runs.model'; 3 | export * from './component.model'; 4 | export * from './event.model'; 5 | export * from './integrations.model'; 6 | export * from './journey.model'; 7 | export * from './instance.model'; 8 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/models/integrations.model.ts: -------------------------------------------------------------------------------- 1 | export interface IntegrationV1 { 2 | integration_name: 'TESTGEN'; 3 | } 4 | 5 | export interface TestgenTestOutcomeIntegrationV1 extends IntegrationV1 { 6 | integration_name: 'TESTGEN'; 7 | table: string; 8 | columns?: string[]; 9 | test_suite: string; 10 | version: number; 11 | test_parameters: Parameter[]; 12 | } 13 | 14 | interface Parameter { 15 | name: string; 16 | value: string | number; 17 | } 18 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/services/auth/auth.model.ts: -------------------------------------------------------------------------------- 1 | export const cookieKeys = { 2 | token: 'access_token', 3 | }; 4 | export const cookiePath = '/'; 5 | 6 | export const localStorageKeys = { 7 | loginRedirect: 'login_redirect', 8 | }; 9 | 10 | export enum AuthProviderType { 11 | Auth0 = 'auth0', 12 | OpenID = 'openId', 13 | } 14 | 15 | export interface AuthProvider { 16 | type: AuthProviderType; 17 | is_sso: boolean; 18 | } 19 | 20 | export interface Auth0AuthProvider extends AuthProvider { 21 | type: AuthProviderType.Auth0; 22 | } 23 | 24 | export interface OpenIDAuthProvider extends AuthProvider { 25 | type: AuthProviderType.OpenID; 26 | domain: string; 27 | client_id: string; 28 | client_secret: string; 29 | } 30 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/services/index.ts: -------------------------------------------------------------------------------- 1 | export * from './user/user.model'; 2 | export * from './user/user.service'; 3 | 4 | export * from './auth/auth.model'; 5 | export * from './auth/session.service'; 6 | 7 | export * from './company/company.model'; 8 | export * from './company/company.service'; 9 | 10 | 11 | export * from './organization/organization.model'; 12 | export * from './organization/organization.service'; 13 | 14 | // Projects 15 | export * from './project/project.model'; 16 | export * from './project/project.service'; 17 | export * from './project/project.store'; 18 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/services/organization/organization.model.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '../../entity'; 2 | 3 | export interface Organization extends Entity { 4 | company: string; 5 | } 6 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/services/organization/organization.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Organization } from './organization.model'; 3 | import { EntityService, EntityType } from '../../entity'; 4 | 5 | @Injectable({ providedIn: 'root' }) 6 | export class OrganizationService extends EntityService { 7 | protected override baseEntity = EntityType.Organization; 8 | protected override parentEntity = EntityType.Company; 9 | } 10 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/services/user/user.model.ts: -------------------------------------------------------------------------------- 1 | import { Entity, EntityType, Role } from '../../entity'; 2 | import { Company } from '../company/company.model'; 3 | 4 | export interface User extends Entity { 5 | email: string; 6 | job_title: string; 7 | job_function: string; 8 | primary_company: string; 9 | admin: boolean; 10 | roles?: UserRoleAssignment[]; 11 | } 12 | 13 | export interface ExpandedUser extends Omit { 14 | created_by: User; 15 | primary_company: Company; 16 | } 17 | 18 | export interface UserRoleAssignment extends Role { 19 | assignments: { [entityType in EntityType]?: number[] }; 20 | } 21 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/services/user/user.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { User } from './user.model'; 3 | import { Observable } from 'rxjs'; 4 | import { EntityListResponse, EntityService, EntityType } from '../../entity'; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class UserService extends EntityService { 10 | 11 | override baseEntity = EntityType.User; 12 | 13 | getUsersByCompany(companyId: number): Observable> { 14 | return this.http.get>(`${this.apiBaseUrl}/${this.prefix}/v1/companies/${companyId}/users`); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/templating/index.ts: -------------------------------------------------------------------------------- 1 | export * from './abstract-templating.directive'; 2 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/utilities/tools.utilities.spec.ts: -------------------------------------------------------------------------------- 1 | import { listEnvVariableFormatter } from './tools.utilities'; 2 | 3 | describe('listEnvVariableFormatter', () => { 4 | it('should generate list value correctly for script', () => { 5 | const testCases = [ 6 | { input: '', output: '[]' }, 7 | { input: null, output: '[]' }, 8 | { input: ' ', output: '[]' }, 9 | { input: 'pip', output: '[\\"pip\\"]' }, 10 | { input: 'pip1,pip2', output: '[\\"pip1\\",\\"pip2\\"]' }, 11 | { input: ' pip1 , pip2 ', output: '[\\"pip1\\",\\"pip2\\"]' }, 12 | ]; 13 | testCases.forEach(({ input, output }) => { 14 | expect(listEnvVariableFormatter(input)).toEqual(output); 15 | }); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/lib/utilities/tools.utilities.ts: -------------------------------------------------------------------------------- 1 | export function listEnvVariableFormatter(value: string | null): string { 2 | const trimmed = value?.trim(); 3 | if (!trimmed) { 4 | return '[]'; 5 | } 6 | const trimmedArray = trimmed.split(',').map(item => item?.trim()); 7 | return JSON.stringify(JSON.stringify(trimmedArray)).slice(1, -1); 8 | } 9 | -------------------------------------------------------------------------------- /observability_ui/libs/core/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /observability_ui/libs/core/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "inlineSources": true, 8 | "types": [] 9 | }, 10 | "exclude": [ 11 | "src/test-setup.ts", 12 | "**/*.spec.ts", 13 | "**/*.test.ts", 14 | "src/testing/*.ts", 15 | "jest.config.ts" 16 | ], 17 | "include": ["**/*.ts"] 18 | } 19 | -------------------------------------------------------------------------------- /observability_ui/libs/core/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"], 7 | "target": "es2016" 8 | }, 9 | "files": ["src/test-setup.ts"], 10 | "include": [ 11 | "**/*.test.ts", 12 | "**/*.spec.ts", 13 | "**/*.d.ts", 14 | "src/testing/*.ts", 15 | "jest.config.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /observability_ui/libs/translate/README.md: -------------------------------------------------------------------------------- 1 | # translate 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test translate` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /observability_ui/libs/translate/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@observability/translate", 3 | "version": "2.0.0", 4 | "description": "this is the core lib of observability mfe setup", 5 | "license": "MIT" 6 | } 7 | -------------------------------------------------------------------------------- /observability_ui/libs/translate/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/translation.module'; 2 | export * from './lib/translation.service'; 3 | export * from './lib/translate.pipe'; 4 | 5 | export * from './lib/translate.pipe.mock'; 6 | -------------------------------------------------------------------------------- /observability_ui/libs/translate/src/lib/translate.pipe.mock.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'translate', 5 | }) 6 | export class TranslatePipeMock implements PipeTransform { 7 | transform(key: string): string { 8 | return key; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /observability_ui/libs/translate/src/lib/translate.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import { TranslationService } from './translation.service'; 3 | 4 | @Pipe({ 5 | name: 'translate', 6 | }) 7 | export class TranslatePipe implements PipeTransform { 8 | constructor(private translationService: TranslationService) { 9 | } 10 | 11 | public transform(key: string, params?: object, defaultTo?: string): string { 12 | const translation = this.translationService.translate(key, params); 13 | if (translation === key && defaultTo) { 14 | return defaultTo; 15 | } 16 | return translation; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /observability_ui/libs/translate/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /observability_ui/libs/translate/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "inlineSources": true, 8 | "types": [] 9 | }, 10 | "exclude": [ 11 | "src/test-setup.ts", 12 | "**/*.spec.ts", 13 | "**/*.test.ts", 14 | "jest.config.ts" 15 | ], 16 | "include": ["**/*.ts"] 17 | } 18 | -------------------------------------------------------------------------------- /observability_ui/libs/translate/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"], 7 | "target": "es2016" 8 | }, 9 | "files": ["src/test-setup.ts"], 10 | "include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts", "jest.config.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/README.md: -------------------------------------------------------------------------------- 1 | # ui 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test ui` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@observability/ui", 3 | "version": "2.0.0", 4 | "description": "this is the core lib of observability mfe setup", 5 | "license": "MIT", 6 | "scripts": { 7 | "make:linkable": "yarn link" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/breadcrumb/breadcrumb.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | {{item.label}} 7 | 8 | 9 | 11 | {{item.label}} 12 | 13 | 14 | 16 | navigate_next 17 | 18 | 19 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/breadcrumb/breadcrumb.component.scss: -------------------------------------------------------------------------------- 1 | @import '../../../styles/mixins'; 2 | 3 | :host { 4 | @include flex-row($justify: flex-start); 5 | @include font-style(caption, secondary); 6 | 7 | line-height: 14px; 8 | } 9 | 10 | .breadcrumb__link { 11 | @include link(secondary); 12 | } 13 | 14 | .breadcrumb__icon { 15 | @include icon-size(16px); 16 | } 17 | 18 | .breadcrumb__item, 19 | .breadcrumb__link { 20 | &:last-child { 21 | @include font-color(primary); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/breadcrumb/breadcrumb.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, ComponentFixture } from '@angular/core/testing'; 2 | import { BreadcrumbComponent } from './breadcrumb.component'; 3 | 4 | describe('Breadcrumb Component', () => { 5 | let fixture: ComponentFixture; 6 | let component: BreadcrumbComponent; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({ 10 | imports: [], 11 | declarations: [], 12 | providers: [], 13 | }); 14 | 15 | fixture = TestBed.createComponent(BreadcrumbComponent); 16 | component = fixture.componentInstance; 17 | }); 18 | 19 | it('should exist', () => { 20 | expect(component).toBeDefined(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/breadcrumb/breadcrumb.component.ts: -------------------------------------------------------------------------------- 1 | import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; 2 | import { BreadcrumbItem } from './breadcrumb.model'; 3 | 4 | 5 | @Component({ 6 | selector: 'breadcrumb', 7 | templateUrl: 'breadcrumb.component.html', 8 | styleUrls: [ 'breadcrumb.component.scss' ], 9 | changeDetection: ChangeDetectionStrategy.OnPush, 10 | }) 11 | export class BreadcrumbComponent { 12 | 13 | @Input() items!: BreadcrumbItem[]; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/breadcrumb/breadcrumb.model.ts: -------------------------------------------------------------------------------- 1 | export interface BreadcrumbItem { 2 | label: string; 3 | link?: string | any[]; 4 | } 5 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/breadcrumb/breadcrumb.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { MatIconModule } from '@angular/material/icon'; 4 | import { RouterModule } from '@angular/router'; 5 | import { BreadcrumbComponent } from './breadcrumb.component'; 6 | 7 | 8 | @NgModule({ 9 | imports: [ 10 | CommonModule, 11 | MatIconModule, 12 | RouterModule, 13 | ], 14 | exports: [ BreadcrumbComponent ], 15 | declarations: [ BreadcrumbComponent ], 16 | providers: [], 17 | }) 18 | export class BreadcrumbModule { 19 | } 20 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/code-snippet/code-snippet.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | {{'code' | translate}} 4 |
6 | {{copied ? 'check' : 'content_copy'}} 7 | {{(copied ? 'copied' : 'copy') | translate}} 8 |
9 |
10 |
11 | 12 |
13 |
14 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/dag/dag-edge.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, Input } from '@angular/core'; 2 | import { DagEdge } from './dag.model'; 3 | 4 | @Directive({ 5 | selector: 'dag-edge', 6 | }) 7 | export class DagEdgeDirective implements DagEdge { 8 | @Input() public id!: string; 9 | @Input() public fromNode!: string; 10 | @Input() public toNode!: string; 11 | 12 | public path: string = ''; 13 | public selected: boolean = false; 14 | public points: Array<{x: number; y: number}> = []; 15 | } 16 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/dag/dag-legend.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive } from '@angular/core'; 2 | 3 | @Directive({ 4 | selector: '[dagLegend]', 5 | }) 6 | export class DagLegendDirective {} 7 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/dag/dag.model.ts: -------------------------------------------------------------------------------- 1 | export enum DagOrientation { 2 | Horizontal = 'HORIZONTAL', 3 | Vertical = 'VERTICAL', 4 | } 5 | 6 | export interface DagEdge { 7 | path: string; 8 | points: Array<{x: number; y: number}>; 9 | } 10 | 11 | export interface DraggedDagEdge extends DagEdge { 12 | offset: { x: number, y: number }; 13 | sourceNodeId: string; 14 | } 15 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/dag/dag.translation.ts: -------------------------------------------------------------------------------- 1 | 2 | export const dagTranslations = { 3 | dag: { 4 | renderingError: 'Unable to render the graph', 5 | errorAction: 'Refresh', 6 | 7 | zoom: { 8 | in: 'Zoom In', 9 | out: 'Zoom Out', 10 | toFit: 'Zoom to Fit', 11 | }, 12 | 13 | arrange: { 14 | leftToRight: 'Align Left-Right', 15 | topToBottom: 'Align Top-Bottom', 16 | }, 17 | 18 | legend: { 19 | show: 'Show legend', 20 | hide: 'Hide legend', 21 | }, 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/dag/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dag.module'; 2 | 3 | export * from './dag.component'; 4 | 5 | export * from './dag-node.directive'; 6 | export * from './dag-edge.directive'; 7 | export * from './dag-legend.directive'; 8 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/details-header/details-header.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 | arrow_back 6 | {{ backLinkTitle }} 7 | 8 | 9 | 10 |
11 |
{{ title || '...' }}
12 |
13 | 14 |
15 |
16 | 17 | 18 |
19 | 20 |
21 | 22 |
23 |
24 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/details-header/details-header.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'details-header', 5 | templateUrl: 'details-header.component.html', 6 | styleUrls: [ 'details-header.component.scss' ], 7 | }) 8 | export class DetailsHeaderComponent { 9 | @Input() title!: string; 10 | @Input() subTitle!: string; 11 | @Input() backLink!: string | string[]; 12 | @Input() backLinkTitle!: string; 13 | } 14 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/details-header/index.ts: -------------------------------------------------------------------------------- 1 | export * from './details-header.module'; 2 | export * from './details-header.component'; 3 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/directives/dynamic-component/dynamic-component.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { DynamicComponentOutletDirective } from './dynamic-component-outlet.directive'; 3 | 4 | @NgModule({ 5 | imports: [], 6 | exports: [ 7 | DynamicComponentOutletDirective, 8 | ], 9 | declarations: [ 10 | DynamicComponentOutletDirective, 11 | ], 12 | providers: [], 13 | }) 14 | export class DynamicComponentModule { 15 | } 16 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/directives/dynamic-component/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dynamic-component.module'; 2 | export * from './dynamic-component-outlet.directive'; 3 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/directives/index.ts: -------------------------------------------------------------------------------- 1 | export * from './bind-query-params/bind-query-params.module'; 2 | export * from './bind-query-params/to-mat-paginator/bind-query-params-mat-paginator.directive'; 3 | export * from './bind-query-params/to-mat-sort/bind-query-params-mat-sort.directive'; 4 | export * from './bind-query-params/to-mat-tab/bind-query-params-mat-tab.directive'; 5 | 6 | export * from './dynamic-component/dynamic-component.module'; 7 | export * from './dynamic-component/dynamic-component-outlet.directive'; 8 | 9 | export * from './click-confirm/click-confirm.directive'; 10 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/dk-tooltip/click-listener.service.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Injectable } from '@angular/core'; 2 | import { Observable, Subject } from 'rxjs'; 3 | import { DOCUMENT } from '@angular/common'; 4 | 5 | @Injectable({ 6 | providedIn: 'root', 7 | }) 8 | export class ClickListenerService { 9 | 10 | private _onClick: Subject = new Subject(); 11 | 12 | constructor(@Inject(DOCUMENT) private document: Document) { 13 | this.document.addEventListener('click', this.clicked.bind(this)); 14 | } 15 | 16 | get onClick(): Observable { 17 | return this._onClick.asObservable(); 18 | } 19 | 20 | private clicked($event: MouseEvent) { 21 | this._onClick.next($event); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/dk-tooltip/index.ts: -------------------------------------------------------------------------------- 1 | export * from './click-listener.service'; 2 | export * from './dk-tooltip.component'; 3 | export * from './dk-tooltip.directive'; 4 | export * from './dk-tooltip.module'; 5 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/dots-chart/dot-template.directive.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | 3 | import { Directive, Input, TemplateRef } from '@angular/core'; 4 | 5 | @Directive({ 6 | selector: '[dotTpl]', 7 | standalone: true, 8 | }) 9 | export class DotTemplateDirective { 10 | @Input('dotTpl') value!: object; 11 | 12 | constructor(public template: TemplateRef) {} 13 | } 14 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/dots-chart/dot.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { DotComponent } from './dot.component'; 3 | 4 | describe('DotComponent', () => { 5 | let fixture: ComponentFixture; 6 | let component: DotComponent; 7 | 8 | beforeEach(async () => { 9 | TestBed.configureTestingModule({ 10 | imports: [ 11 | DotComponent, 12 | ], 13 | }); 14 | 15 | fixture = TestBed.createComponent(DotComponent); 16 | component = fixture.componentInstance; 17 | 18 | fixture.detectChanges(); 19 | }); 20 | 21 | it('should create', () => { 22 | expect(component).toBeDefined(); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/dots-chart/dot.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, HostBinding, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'dot', 5 | template: ``, 6 | styleUrls: ['dot.component.scss'], 7 | standalone: true, 8 | }) 9 | export class DotComponent { 10 | @HostBinding('class') @Input() status!: 'ACTIVE' | 'COMPLETED' | 'WARNING' | 'ERROR' | 'UPCOMING'; 11 | @HostBinding('class.has-runs') @Input() hasRuns!: boolean; 12 | } 13 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/dots-chart/drill-in.directive.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | 3 | import { Directive, TemplateRef } from '@angular/core'; 4 | 5 | @Directive({ 6 | selector: '[drillInTemplate]', 7 | standalone: true, 8 | }) 9 | export class DrillInTemplateDirective { 10 | constructor(public template: TemplateRef) {} 11 | } 12 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/duration/duration.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'duration', 5 | template: `{{ (start|date:dateFormat)|duration:(end|date:dateFormat)}}` 6 | }) 7 | export class DurationComponent implements OnInit { 8 | 9 | @Input() start!: string; 10 | @Input() end!: string; 11 | 12 | dateFormat = 'EEEE, MMMM d, y, h:mm:ss a zzzz'; 13 | 14 | ngOnInit() { 15 | if (!this.end) { 16 | this.end = new Date().getTime().toString(); 17 | } 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/duration/duration.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { DurationPipe } from './duration.pipe'; 3 | import { DurationComponent } from './duration.component'; 4 | import { CommonModule } from '@angular/common'; 5 | 6 | @NgModule({ 7 | imports: [ CommonModule ], 8 | declarations: [ DurationPipe, DurationComponent ], 9 | exports: [ DurationPipe, DurationComponent ] 10 | }) 11 | export class DurationModule {} 12 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/duration/index.ts: -------------------------------------------------------------------------------- 1 | export * from './duration.module'; 2 | export * from './duration.pipe'; 3 | export * from './duration.component'; 4 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/empty-state-setup/empty-state-setup.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/empty-state-setup/empty-state-setup.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'empty-state-setup', 5 | templateUrl: './empty-state-setup.component.html', 6 | styleUrls: ['./empty-state-setup.component.scss'], 7 | standalone: true, 8 | }) 9 | export class EmptyStateSetupComponent {} 10 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/entity/active-status-chip/active-status-chip.component.html: -------------------------------------------------------------------------------- 1 | 2 | {{ (active ? 'active' : 'inactive') | translate }} 3 | 4 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/entity/active-status-chip/active-status-chip.component.ts: -------------------------------------------------------------------------------- 1 | import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; 2 | 3 | 4 | @Component({ 5 | selector: 'active-status-chip', 6 | templateUrl: 'active-status-chip.component.html', 7 | changeDetection: ChangeDetectionStrategy.OnPush, 8 | }) 9 | export class ActiveStatusChipComponent { 10 | 11 | @Input() active!: boolean; 12 | } 13 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/entity/entity-list-placeholder/entity-list-placeholder.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 6 | 7 | 8 | 9 | {{ (hasFilters ? 'noEntitiesForFilters' : 'noEntitiesFound') | translate:{entity: entity} }} 10 | 11 |
12 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/entity/entity-list-placeholder/entity-list-placeholder.component.scss: -------------------------------------------------------------------------------- 1 | @use "@observability/ui/styles/mixins" as mixins; 2 | @import "@observability/ui/styles/variables"; 3 | 4 | 5 | $placeholder-height: 200px; 6 | 7 | div { 8 | @include mixins.font-style(subheader, secondary); 9 | @include mixins.flex-row($justify: center, $align: center); 10 | 11 | height: $placeholder-height; 12 | border-bottom: $border; 13 | } 14 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/entity/entity-list-placeholder/entity-list-placeholder.component.ts: -------------------------------------------------------------------------------- 1 | import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; 2 | 3 | 4 | @Component({ 5 | selector: 'entity-list-placeholder', 6 | styleUrls: [ 'entity-list-placeholder.component.scss' ], 7 | templateUrl: 'entity-list-placeholder.component.html', 8 | changeDetection: ChangeDetectionStrategy.OnPush, 9 | }) 10 | export class EntityListPlaceholderComponent { 11 | 12 | @Input() entity!: string; 13 | @Input() loading!: boolean; 14 | @Input() total!: number; 15 | @Input() hasFilters!: boolean; 16 | } 17 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/entity/index.ts: -------------------------------------------------------------------------------- 1 | export * from './entity.module'; 2 | 3 | export * from './entity-list-placeholder/entity-list-placeholder.component'; 4 | 5 | export * from './active-status-chip/active-status-chip.component'; 6 | 7 | export * from './nullify-pending/nullify-pending.pipe'; 8 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/entity/nullify-pending/nullify-pending.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({name: 'nullifyPending'}) 4 | export class NullifyPendingPipe implements PipeTransform { 5 | 6 | transform(value: T) { 7 | if (typeof value === 'string') { 8 | return value.startsWith('_DK_PENDING_') ? null : value; 9 | } 10 | return value; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/expansion-panel/expansion-panel-content/expansion-panel-content.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'expansion-panel-content', 5 | template: ``, 6 | }) 7 | export class ExpansionPanelContentComponent {} 8 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/expansion-panel/expansion-panel-title/expansion-panel-title.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'expansion-panel-title', 5 | template: `` 6 | }) 7 | export class ExpansionPanelTitleComponent {} 8 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/expansion-panel/expansion-panel/expansion-panel.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{open ? 'arrow_drop_down' : 'arrow_right'}} 4 | 5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/expansion-panel/expansion-panel/expansion-panel.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: flex; 3 | flex-direction: row; 4 | } 5 | 6 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/expansion-panel/expansion-panel/expansion-panel.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'expansion-panel', 5 | templateUrl: 'expansion-panel.component.html' , 6 | styleUrls: [ 'expansion-panel.component.scss' ], 7 | }) 8 | export class ExpansionPanelComponent { 9 | @Input() open: boolean = false; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/expansion-panel/index.ts: -------------------------------------------------------------------------------- 1 | export * from './expansion-panel.module'; 2 | export * from './expansion-panel/expansion-panel.component'; 3 | 4 | export * from './expansion-panel-title/expansion-panel-title.component'; 5 | export * from './expansion-panel-content/expansion-panel-content.component'; 6 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/fields/checkbox-field/checkbox-field.component.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | {{label}} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | help_outline 19 | 20 | 21 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/fields/checkbox-field/checkbox-field.component.scss: -------------------------------------------------------------------------------- 1 | @import '@observability/ui/styles/fields'; 2 | 3 | 4 | :host { 5 | @include field; 6 | 7 | justify-content: flex-start; 8 | margin: $field-margin-top 0 $field-margin-bottom; 9 | 10 | &.form-field--no-margin-top { 11 | margin-top: 0; 12 | } 13 | 14 | &.form-field--indent { 15 | padding-left: 28px; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/fields/schedule-field/schedule.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import cronstrue from 'cronstrue'; 3 | import { Schedule } from '@observability-ui/core'; 4 | 5 | @Pipe({ 6 | name: 'schedule', 7 | }) 8 | export class SchedulePipe implements PipeTransform { 9 | public transform(schedule?: Schedule | null): string { 10 | if (!schedule?.schedule) { 11 | return '...'; 12 | } 13 | 14 | return `${cronstrue.toString(schedule.schedule).replace('At ', '').toLowerCase()}${schedule.timezone ? ' (' + schedule.timezone + ')' : ''}`; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/fields/text-field/text-field-error.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, TemplateRef, ViewChild } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'text-field-error', 5 | template: ` 6 | 7 | 8 | 9 | ` 10 | }) 11 | export class TextFieldErrorComponent { 12 | 13 | @Input() type!: string; 14 | 15 | @ViewChild(TemplateRef, { static: true }) template!: TemplateRef; 16 | } 17 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/fields/text-field/text-field.component.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/mixins' as mixins; 2 | 3 | :host { 4 | display: flex; 5 | flex-direction: column; 6 | } 7 | 8 | mat-icon { 9 | @include mixins.font-color(secondary); 10 | 11 | height: 1em; 12 | font-size: 100% !important; 13 | } 14 | 15 | .search-icon { 16 | margin-right: 4px; 17 | } 18 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/fields/timespan-field/timespan-field.component.scss: -------------------------------------------------------------------------------- 1 | .nowrap { 2 | white-space: nowrap; 3 | } 4 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/fields/timespan-field/timespan.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'timespan' 5 | }) 6 | 7 | export class TimespanPipe implements PipeTransform { 8 | transform(value: number): string { 9 | if (Number.isInteger(value / 86400)) { 10 | return `${value / 86400} days`; 11 | } else if (Number.isInteger(value / 3600)) { 12 | return `${value / 3600} hours`; 13 | } 14 | 15 | return `${value / 60} minutes`; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/fields/timespan-field/timespan.translation.ts: -------------------------------------------------------------------------------- 1 | export const timespanTranslation = { 2 | days: 'days', 3 | hours: 'hours', 4 | minutes: 'minutes' 5 | }; 6 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/gantt-chart/gantt-chart.model.ts: -------------------------------------------------------------------------------- 1 | import { GanttBarDirective } from './gantt-bar.directive'; 2 | 3 | export interface Position { 4 | offset: number; 5 | duration: number; 6 | } 7 | 8 | export interface GanttTaskGroup { 9 | id: string; 10 | label: string; 11 | tasks: GanttBarDirective[]; 12 | children: GanttTaskGroup[]; 13 | start_type: 'DEFAULT' | 'SCHEDULED' | 'BATCH' | 'PAYLOAD', 14 | payload_key?: string; 15 | } 16 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/gantt-chart/gantt-chart.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { GanttChartComponent } from './gantt-chart.component'; 4 | import { GanttTaskComponent } from './gantt-task.component'; 5 | import { GanttBarDirective } from './gantt-bar.directive'; 6 | import { GanttLabelDirective } from './gantt-label.directive'; 7 | 8 | @NgModule({ 9 | imports: [ 10 | CommonModule, 11 | ], 12 | declarations: [ GanttChartComponent, GanttTaskComponent, GanttBarDirective, GanttLabelDirective ], 13 | exports: [ GanttChartComponent, GanttTaskComponent, GanttBarDirective, GanttLabelDirective ] 14 | }) 15 | export class GanttChartModule { 16 | } 17 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/gantt-chart/gantt-label.directive.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | 3 | import { Directive, TemplateRef } from '@angular/core'; 4 | 5 | @Directive({ 6 | selector: '[ganttLabel]', 7 | }) 8 | export class GanttLabelDirective { 9 | constructor( 10 | public template: TemplateRef, 11 | ) {} 12 | } 13 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/is-today/is-today.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import { formatDate } from '@angular/common'; 3 | 4 | @Pipe({ 5 | name: 'isToday', 6 | standalone: true 7 | }) 8 | export class IsTodayPipe implements PipeTransform { 9 | transform(value: any): any { 10 | const today = formatDate(new Date(), 'yyyy.MM.dd', 'en'); 11 | const date = formatDate(value, 'yyyy.MM.dd', 'en'); 12 | 13 | return today === date; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/labeled-menu/index.ts: -------------------------------------------------------------------------------- 1 | export * from './labeled-menu.module'; 2 | export * from './labeled-menu.component'; 3 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/labeled-menu/labeled-menu.component.html: -------------------------------------------------------------------------------- 1 | 13 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/labeled-menu/labeled-menu.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'labeled-menu', 5 | templateUrl: 'labeled-menu.component.html', 6 | styleUrls: [ 'labeled-menu.component.scss' ], 7 | }) 8 | export class LabeledMenuComponent { 9 | 10 | @Input() 11 | public label!: string; 12 | 13 | @Input() 14 | public showDropDownArrow!: boolean; 15 | 16 | @Input() 17 | public id!: string; 18 | 19 | @Input() 20 | public disabled!: boolean; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/labeled-menu/labeled-menu.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { MatButtonModule } from '@angular/material/button'; 3 | import { MatMenuModule } from '@angular/material/menu'; 4 | import { MatIconModule } from '@angular/material/icon'; 5 | import { CommonModule } from '@angular/common'; 6 | import { LabeledMenuComponent } from './labeled-menu.component'; 7 | 8 | 9 | @NgModule({ 10 | imports: [ 11 | MatButtonModule, 12 | MatMenuModule, 13 | MatIconModule, 14 | CommonModule, 15 | ], 16 | exports: [ 17 | LabeledMenuComponent, 18 | ], 19 | declarations: [ 20 | LabeledMenuComponent, 21 | ], 22 | providers: [], 23 | }) 24 | export class LabeledMenuModule { 25 | } 26 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/mat-card-edit/mat-card-edit.component.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/variables' as variables; 2 | @use '@observability/ui/styles/mixins' as mixins; 3 | 4 | .title { 5 | @include mixins.font-style($style: menu); 6 | } 7 | 8 | .edit-icon { 9 | @include mixins.icon-size(16px); 10 | @include mixins.font-color(secondary); 11 | 12 | position: absolute; 13 | top: variables.$space-sm; 14 | right: variables.$space-sm; 15 | cursor: pointer; 16 | } 17 | 18 | mat-card.editing { 19 | padding-bottom: 8px ; 20 | } 21 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/metadata-viewer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './metadata-viewer.module'; 2 | export * from './metadata-viewer.component'; 3 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/pipes/get-integration/get-integration.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import { IntegrationV1 } from '@observability-ui/core'; 3 | 4 | @Pipe({ 5 | name: 'getIntegration', 6 | pure: true, 7 | standalone: true, 8 | }) 9 | export class GetIngrationPipe implements PipeTransform { 10 | transform(integrations: IntegrationV1[], name: IntegrationV1['integration_name']): IntegrationV1 | undefined { 11 | if (!integrations || integrations.length <= 0 || !name) { 12 | return undefined; 13 | } 14 | 15 | return integrations.find(i => i.integration_name === name); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/pipes/humanize/humanize.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'humanize', 5 | pure: true, 6 | standalone: true, 7 | }) 8 | export class HumanizePipe implements PipeTransform { 9 | transform(value: string): string { 10 | if (!value) { 11 | return ''; 12 | } 13 | return this.humanize(value); 14 | } 15 | 16 | private humanize(slug: string): string { 17 | return slug.replace(/[_-]/g, ' '); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/pipes/parseDate/parseDate.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import { parseDate } from '@observability-ui/core'; 3 | 4 | @Pipe({ 5 | name: 'parseDate', 6 | standalone: true, 7 | }) 8 | 9 | export class ParseDatePipe implements PipeTransform { 10 | transform(value: string) { 11 | return parseDate(value); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/pipes/sum/sum.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'sum', 5 | standalone: true, 6 | }) 7 | export class SumPipe implements PipeTransform { 8 | transform(items: Array, key?: string) { 9 | return items.reduce((total, item) => total + this.getValue(item, key), 0); 10 | } 11 | 12 | private getValue(item: any, key?: string): number { 13 | if (!key) { 14 | return item; 15 | } 16 | 17 | let result = item; 18 | const parts = key?.trim().split("."); 19 | for (const part of parts) { 20 | result = item[part]; 21 | } 22 | 23 | return result ?? 0; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/selected-actions/selected-actions.component.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/mixins' as mixins; 2 | @use '@observability/ui/styles/variables' as variables; 3 | 4 | :host { 5 | display: flex; 6 | } 7 | 8 | .toggle-button { 9 | background-color: variables.$gray-200; 10 | 11 | --border-radius: 0; 12 | 13 | border-radius: 4px 0 0 4px; 14 | } 15 | 16 | .actions-button { 17 | @include mixins.flex-row(); 18 | 19 | --border-radius: 0; 20 | 21 | border-radius: 0 4px 4px 0; 22 | 23 | &.stand-alone { 24 | border-radius: 4px; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/table-wrapper/header-label.directive.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewInit, Directive, ElementRef, Input } from '@angular/core'; 2 | 3 | @Directive({ 4 | selector: '[headerLabel]', 5 | }) 6 | export class HeaderLabelDirective implements AfterViewInit { 7 | @Input() 8 | headerLabel!: string; 9 | 10 | textContent!: string; 11 | 12 | constructor(public elementRef: ElementRef) { 13 | } 14 | 15 | ngAfterViewInit(): void { 16 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 17 | // @ts-ignore 18 | this.textContent = this.elementRef.nativeElement.textContent.trim(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/table-wrapper/index.ts: -------------------------------------------------------------------------------- 1 | export * from './table-wrapper.module'; 2 | export * from './table-wrapper.component'; 3 | export * from './table-wrapper.model'; 4 | export * from './drag-disabled.directive'; 5 | export * from './header-label.directive'; 6 | export * from './sort-disabled.directive'; 7 | export * from './toggle-disabled.directive'; 8 | export * from './table-wrapper-actions.component'; 9 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/table-wrapper/table-wrapper-actions.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'table-wrapper-actions', 5 | template: ``, 6 | }) 7 | export class TableWrapperActionsComponent { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/table-wrapper/table-wrapper.model.ts: -------------------------------------------------------------------------------- 1 | import { Sort } from '@angular/material/sort'; 2 | 3 | export interface TableChangeEvent { 4 | pageIndex: number; 5 | pageSize: number; 6 | sort?: Sort; 7 | search: TSearch; 8 | } 9 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/table-wrapper/table-wrapper.translation.ts: -------------------------------------------------------------------------------- 1 | 2 | export const translations = { 3 | search: 'Search', 4 | refresh: 'Refresh', 5 | showHideColumns: 'Show/Hide Columns', 6 | noEntitiesFound: 'No {{entities}} found.', 7 | selected: '{{count}} item{{^count.1}}s{{/count.1}} selected' 8 | }; 9 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/truncate/index.ts: -------------------------------------------------------------------------------- 1 | export * from './truncate.directive'; 2 | export * from './truncate.module'; 3 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/truncate/truncate.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { TruncateDirective } from './truncate.directive'; 3 | 4 | @NgModule({ 5 | declarations: [ TruncateDirective ], 6 | exports: [ TruncateDirective ] 7 | }) 8 | export class TruncateModule {} 9 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/lib/ui.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | @NgModule({ 5 | imports: [ CommonModule ], 6 | }) 7 | export class UiModule {} 8 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | 3 | class ResizeObserver { 4 | // eslint-disable-next-line @typescript-eslint/no-empty-function 5 | observe() {} 6 | // eslint-disable-next-line @typescript-eslint/no-empty-function 7 | unobserve() {} 8 | // eslint-disable-next-line @typescript-eslint/no-empty-function 9 | disconnect() {} 10 | } 11 | 12 | window.ResizeObserver = ResizeObserver; 13 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/styles/_details-page.scss: -------------------------------------------------------------------------------- 1 | @use './_mixins' as mixins; 2 | @use './_variables' as variables; 3 | 4 | details-header { 5 | @include mixins.flex-column($justify: unset, $align: baseline); 6 | 7 | background: white; 8 | border-bottom: variables.$border; 9 | padding: variables.$space-sm variables.$space-lg 0 variables.$space-lg; 10 | 11 | nav { 12 | min-width: calc(100vw - 64px); 13 | border-bottom: unset !important; 14 | 15 | .mat-drawer-opened ~ mat-sidenav-content & { 16 | min-width: calc(100vw - 264px); 17 | } 18 | 19 | .mat-tab-link { 20 | min-width: 100px; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/styles/_fields.scss: -------------------------------------------------------------------------------- 1 | @use 'variables' as variables; 2 | @import 'mixins'; 3 | 4 | $field-max-width: 700px; 5 | $field-max-width: 700px; 6 | $field-group-width: 500px; 7 | $field-group-width-medium: 450px; 8 | $field-group-width-narrow: 400px; 9 | $field-group-width-narrower: 350px; 10 | $field-margin-top: 0.85em; 11 | $field-margin-bottom: 20px; 12 | $field-color: variables.$gray-500; 13 | $field-shadow: rgba(variables.$black, 0.3); 14 | $field-label-width: 200px; 15 | $field-label-min-width: 120px; 16 | 17 | 18 | 19 | @mixin field($max-width: $field-max-width) { 20 | @include flex-row($justify: space-between); 21 | max-width: $max-width; 22 | color: variables.$dark-primary-text; 23 | } 24 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/styles/_icon-size.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/mixins' as mixins; 2 | 3 | $size-shortcuts: ("icon-size": "icon-size"); 4 | 5 | $range-start: 10; 6 | $range-end: 100; 7 | 8 | $range-values: (); 9 | 10 | @for $i from $range-start through $range-end { 11 | $range-values: append($range-values, $i); 12 | } 13 | 14 | @each $property, $shortcut in $size-shortcuts { 15 | @each $value in $range-values { 16 | // Do something with each value 17 | // For example, print the value 18 | mat-icon.#{$shortcut}-#{$value} { 19 | @include mixins.icon-size(#{$value}px !important); 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/styles/_overlay.scss: -------------------------------------------------------------------------------- 1 | @use '@observability/ui/styles/variables' as variables; 2 | 3 | .base-overlay { 4 | overflow: hidden; 5 | border-radius: 4px; 6 | outline: 0; 7 | min-height: 64px; 8 | background: variables.$white; 9 | } 10 | 11 | .opaque-overlay { 12 | min-width: 112px; 13 | max-width: 280px; 14 | overflow: hidden; 15 | border-radius: 4px; 16 | outline: 0; 17 | min-height: 64px; 18 | background: variables.$white; 19 | } 20 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/styles/material/colors.scss: -------------------------------------------------------------------------------- 1 | @import '../variables'; 2 | 3 | .mat-gray { 4 | circle { 5 | stroke: $gray-500; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "forceConsistentCasingInFileNames": true, 15 | "strict": true, 16 | "noImplicitOverride": true, 17 | "noPropertyAccessFromIndexSignature": true, 18 | "noImplicitReturns": true, 19 | "noFallthroughCasesInSwitch": true, 20 | "target": "es2020" 21 | }, 22 | "angularCompilerOptions": { 23 | "strictInjectionParameters": true, 24 | "strictInputAccessModifiers": true, 25 | "strictTemplates": true 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "inlineSources": true, 8 | "types": [] 9 | }, 10 | "exclude": [ 11 | "src/test-setup.ts", 12 | "**/*.spec.ts", 13 | "**/*.test.ts", 14 | "jest.config.ts" 15 | ], 16 | "include": ["**/*.ts"] 17 | } 18 | -------------------------------------------------------------------------------- /observability_ui/libs/ui/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"], 7 | "strictPropertyInitialization": false, 8 | "target": "es2016" 9 | }, 10 | "files": ["src/test-setup.ts"], 11 | "include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts", "jest.config.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /observability_ui/libs/webpack-config/mapped-paths.js: -------------------------------------------------------------------------------- 1 | module.exports.mappedPaths = [ 2 | /* mapped paths to share */ 3 | '@observability-ui/core', 4 | '@observability-ui/ui', 5 | '@observability-ui/translate', 6 | ]; 7 | -------------------------------------------------------------------------------- /observability_ui/libs/webpack-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-config", 3 | "version": "2.0.0", 4 | "description": "this is the shared configuration of observability mfe setup", 5 | "license": "MIT", 6 | "private": true 7 | } 8 | -------------------------------------------------------------------------------- /observability_ui/tools/executors/version/executor.json: -------------------------------------------------------------------------------- 1 | { 2 | "executors": { 3 | "version": { 4 | "implementation": "./impl", 5 | "schema": "./schema.json", 6 | "description": "Updates apps version in ngsw-config.json file." 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /observability_ui/tools/executors/version/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "executors": "./executor.json" 3 | } 4 | -------------------------------------------------------------------------------- /observability_ui/tools/executors/version/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "type": "object", 4 | "cli": "nx", 5 | "properties": {} 6 | } 7 | -------------------------------------------------------------------------------- /observability_ui/tools/tsconfig.tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "../dist/out-tsc/tools", 5 | "rootDir": ".", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": ["node"], 9 | "importHelpers": false 10 | }, 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /rules_engine/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/rules_engine/__init__.py -------------------------------------------------------------------------------- /rules_engine/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/rules_engine/tests/__init__.py -------------------------------------------------------------------------------- /rules_engine/tests/integration/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/rules_engine/tests/integration/__init__.py -------------------------------------------------------------------------------- /rules_engine/tests/unit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/rules_engine/tests/unit/__init__.py -------------------------------------------------------------------------------- /rules_engine/tests/unit/actions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/rules_engine/tests/unit/actions/__init__.py -------------------------------------------------------------------------------- /rules_engine/tests/unit/conftest.py: -------------------------------------------------------------------------------- 1 | from testlib.fixtures.entities import * 2 | from testlib.fixtures.v2_events import * 3 | -------------------------------------------------------------------------------- /run_manager/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/run_manager/__init__.py -------------------------------------------------------------------------------- /run_manager/event_handlers/__init__.py: -------------------------------------------------------------------------------- 1 | from .dataset_handler import * 2 | from .incomplete_instance_handler import * 3 | from .instance_handler import * 4 | from .run_handler import * 5 | from .schedule_handlers import * 6 | from .task_handler import * 7 | from .test_outcome_handler import * 8 | -------------------------------------------------------------------------------- /run_manager/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/run_manager/tests/__init__.py -------------------------------------------------------------------------------- /run_manager/tests/integration/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/run_manager/tests/integration/__init__.py -------------------------------------------------------------------------------- /run_manager/tests/integration/event_handlers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/run_manager/tests/integration/event_handlers/__init__.py -------------------------------------------------------------------------------- /run_manager/tests/unit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/run_manager/tests/unit/__init__.py -------------------------------------------------------------------------------- /scheduler/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/scheduler/__init__.py -------------------------------------------------------------------------------- /scheduler/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/scheduler/tests/__init__.py -------------------------------------------------------------------------------- /scheduler/tests/integration/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/scheduler/tests/integration/__init__.py -------------------------------------------------------------------------------- /scheduler/tests/unit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/scheduler/tests/unit/__init__.py -------------------------------------------------------------------------------- /scripts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/scripts/__init__.py -------------------------------------------------------------------------------- /scripts/invocations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/scripts/invocations/__init__.py -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | # This file is here to support editable installs (pip install -e .) 2 | # https://github.com/pypa/setuptools/issues/2816 3 | -------------------------------------------------------------------------------- /subcommand/README.md: -------------------------------------------------------------------------------- 1 | ## Subcommand Module 2 | This module provides a basis for creating tools with subcommands. It isolates some dynamic class creation & metaclass 3 | fun into a module that makes creating command line tools simpler to build. 4 | 5 | Check out the ``cli`` tool for example usage. 6 | -------------------------------------------------------------------------------- /subcommand/__init__.py: -------------------------------------------------------------------------------- 1 | from .subcmd import SubcommandBase 2 | 3 | __all__ = ("SubcommandBase",) 4 | -------------------------------------------------------------------------------- /subcommand/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/subcommand/tests/__init__.py -------------------------------------------------------------------------------- /testlib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/testlib/__init__.py -------------------------------------------------------------------------------- /testlib/fixtures/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataKitchen/dataops-observability/fedfa3dbb2ae8252d68b6d666f1ebf02e1c83269/testlib/fixtures/__init__.py -------------------------------------------------------------------------------- /testlib/peewee.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | from unittest.mock import Mock, patch 3 | 4 | 5 | @contextlib.contextmanager 6 | def patch_select(target: str, **kwargs): 7 | with patch(target=f"{target}.select") as select_mock: 8 | select_mock.return_value = select_mock 9 | for attr in ("join", "left_outer_join", "switch", "order_by", "where"): 10 | getattr(select_mock, attr).return_value = select_mock 11 | result_mock = Mock(**kwargs) 12 | for attr in ("get", "get_by_id", "__iter__"): 13 | setattr(select_mock, attr, result_mock) 14 | yield result_mock 15 | --------------------------------------------------------------------------------