├── .dockerignore ├── .editorconfig ├── .githooks └── pre-commit ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── release-template.md └── workflows │ ├── build-image.yml │ ├── build-rolling-image.yml │ ├── docs.yml │ ├── go.yml │ ├── linter.yml │ ├── load-test.yml │ └── release.yml ├── .gitignore ├── .publisher.yml ├── .vscode └── settings.json ├── CHANGELOG.md ├── CLA.md ├── CONTRIBUTING.md ├── Dockerfile.dev ├── ENT-CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── RELEASE.md ├── VERSION ├── api ├── api.go ├── dashboard_integration_test.go ├── filter_integration_test.go ├── handlers │ ├── auth.go │ ├── configuration.go │ ├── dashboard.go │ ├── delivery_attempt.go │ ├── endpoint.go │ ├── event.go │ ├── event_delivery.go │ ├── event_types.go │ ├── filter.go │ ├── handlers.go │ ├── license.go │ ├── main.go │ ├── meta_event.go │ ├── middleware.go │ ├── organisation.go │ ├── organisation_invite.go │ ├── organisation_member.go │ ├── portal_link.go │ ├── project.go │ ├── security.go │ ├── source.go │ ├── subscription.go │ └── user.go ├── ingest.go ├── ingest_integration_test.go ├── ingest_test.go ├── migrations.go ├── migrations │ ├── v20240101 │ │ ├── common.go │ │ ├── create_endpoint_migration.go │ │ ├── create_endpoint_migration_test.go │ │ ├── get_endpoint_migration.go │ │ ├── get_endpoints_migration.go │ │ └── update_endpoint_migration.go │ └── v20240401 │ │ ├── common.go │ │ ├── create_endpoint_migration.go │ │ ├── create_endpoint_migration_test.go │ │ ├── get_endpoint_migration.go │ │ ├── get_endpoints_migration.go │ │ └── update_endpoint_migration.go ├── models │ ├── configuration.go │ ├── endpoint.go │ ├── event.go │ ├── event_delivery.go │ ├── event_types.go │ ├── filter.go │ ├── meta_event.go │ ├── models.go │ ├── portal_link.go │ ├── project.go │ ├── source.go │ ├── source_test.go │ ├── sso.go │ ├── subscription.go │ └── user.go ├── policies │ ├── organisation_policy.go │ ├── organisation_policy_test.go │ ├── policy.go │ ├── policy_test.go │ ├── project_policy.go │ └── project_policy_test.go ├── portal_api_integration_test.go ├── public_integration_test.go ├── server_suite_test.go ├── testdata │ ├── Auth_Config │ │ ├── basic-convoy.json │ │ ├── full-convoy-with-all-realms.json │ │ ├── full-convoy-with-jwt-realm.json │ │ ├── full-convoy-with-native-auth-realm.json │ │ ├── full-convoy.json │ │ ├── jwt-convoy-signup-disabled.json │ │ ├── jwt-convoy-signup-enabled.json │ │ ├── jwt-convoy.json │ │ ├── no-auth-convoy.json │ │ └── none-convoy.json │ ├── TestApplicationHandler_BatchRetryEventDelivery │ │ ├── should_batch_retry_all_successfully.golden │ │ ├── should_batch_retry_one_successfully.golden │ │ ├── should_fail_to_find_app_endpoint.golden │ │ ├── should_fail_to_load_event_deliveries.golden │ │ ├── should_fail_to_update_app_endpoints_status.golden │ │ ├── should_fail_to_update_status_of_event_delivery.golden │ │ └── should_fail_to_write_to_queue.golden │ ├── TestApplicationHandler_CountAffectedEventDeliveries │ │ ├── should_count_affected_event_deliveries_successfully.golden │ │ └── should_fail_to_count_affected_event_deliveries.golden │ ├── TestApplicationHandler_CreateAPIKey │ │ ├── create_api_key.golden │ │ ├── create_api_key_without_expires_at_field.golden │ │ ├── invalid_expiry_date.golden │ │ └── invalid_role.golden │ ├── TestApplicationHandler_CreateApp │ │ ├── invalid_request.golden │ │ ├── invalid_request_-_no_app_name.golden │ │ ├── should_fail_for_application_name_not_unique.golden │ │ ├── should_fail_to_check_if_application_name_is_unique.golden │ │ └── valid_application.golden │ ├── TestApplicationHandler_CreateAppEndpoint │ │ ├── should_error_for_invalid_rate_limit_duration.golden │ │ └── valid_endpoint.golden │ ├── TestApplicationHandler_CreateAppPortalAPIKey │ │ ├── app_id_does_not_belong_to_group.golden │ │ └── create_api_key.golden │ ├── TestApplicationHandler_CreateGroup │ │ ├── invalid_request_-_no_group_hash_field.golden │ │ ├── invalid_request_-_no_group_header_field.golden │ │ ├── invalid_request_-_no_group_interval_seconds_field.golden │ │ ├── invalid_request_-_no_group_name.golden │ │ ├── invalid_request_-_no_group_retry_limit_field.golden │ │ ├── invalid_request_-_no_group_strategy_type_field.golden │ │ ├── invalid_request_-_unsupported_group_hash_field.golden │ │ ├── invalid_request_-_unsupported_group_strategy_type.golden │ │ ├── should_fail_to_create_group.golden │ │ └── valid_group.golden │ ├── TestApplicationHandler_DeleteGroup │ │ ├── failed_group_apps_delete.golden │ │ ├── failed_group_delete.golden │ │ ├── failed_group_events_delete.golden │ │ └── valid_group_delete.golden │ ├── TestApplicationHandler_ForceResendEventDelivery │ │ ├── should_error_for_discarded_event_status.golden │ │ ├── should_error_for_endpoint_not_found.golden │ │ ├── should_error_for_failed_to_fetch_deliveries.golden │ │ ├── should_error_for_failed_to_update_event_delivery_status.golden │ │ ├── should_error_for_inactive_endpoint.golden │ │ ├── should_error_for_malformed_body.golden │ │ └── should_force_resend_all_successfully.golden │ ├── TestApplicationHandler_GetAPIKeyByID │ │ ├── should_fail_to_find_api_key.golden │ │ └── should_find_api_key.golden │ ├── TestApplicationHandler_GetAPIKeys │ │ ├── should_fail_to_load_api_keys.golden │ │ └── should_load_api_keys.golden │ ├── TestApplicationHandler_GetApp │ │ ├── app_not_found.golden │ │ └── valid_application.golden │ ├── TestApplicationHandler_GetAppEndpoint │ │ └── should_get_application_endpoint.golden │ ├── TestApplicationHandler_GetAppEndpoints │ │ └── should_get_application_endpoints.golden │ ├── TestApplicationHandler_GetApps │ │ ├── should_fail_to_fetch_applications.golden │ │ └── valid_applications.golden │ ├── TestApplicationHandler_GetGroup │ │ ├── group_not_found.golden │ │ ├── should_fail_to_count_group_apps.golden │ │ ├── should_fail_to_count_group_messages.golden │ │ └── valid_group.golden │ ├── TestApplicationHandler_GetGroups │ │ ├── should_error_for_invalid_group_access.golden │ │ ├── should_fail_to_fetch_groups.golden │ │ ├── should_fetch_user_groups.golden │ │ └── valid_groups.golden │ ├── TestApplicationHandler_RevokeAPIKey │ │ ├── revoke_api_key.golden │ │ └── should_error_for_revoke_api_key.golden │ ├── TestApplicationHandler_UpdateAPIKey │ │ ├── invalid_role.golden │ │ └── update_api_key.golden │ ├── TestApplicationHandler_UpdateApp │ │ ├── invalid_request.golden │ │ ├── invalid_request_-_no_app_name.golden │ │ ├── should_error_for_duplicate_app_name.golden │ │ ├── valid_application_update.golden │ │ ├── valid_request_-_disable_application.golden │ │ ├── valid_request_-_enable_disabled_application.golden │ │ ├── valid_request_-_update_secret.golden │ │ └── valid_request_-_update_support_email.golden │ ├── TestApplicationHandler_UpdateAppEndpoint │ │ ├── invalid_request.golden │ │ ├── should_error_for_endpoint_not_found.golden │ │ ├── should_error_for_invalid_rate_limit_duration.golden │ │ └── valid_application.golden │ ├── TestApplicationHandler_UpdateAppEndpoint_InvalidRequest │ │ ├── invalid_request.golden │ │ └── valid_application.golden │ ├── TestApplicationHandler_UpdateGroup │ │ ├── invalid_request.golden │ │ ├── invalid_request_-_no_group_name.golden │ │ ├── should_fail_to_update_group.golden │ │ └── valid_group_update.golden │ ├── TestDashboardIntegrationTestSuiteTest │ │ └── TestGetDashboardSummary │ │ │ ├── should_error_for_empty_startDate.golden │ │ │ ├── should_error_for_invalid_startDate.golden │ │ │ ├── should_error_for_invalid_type.golden │ │ │ ├── should_error_for_startDate_greater_than_endDate.golden │ │ │ ├── should_fetch_daily_dashboard_summary.golden │ │ │ ├── should_fetch_monthly_dashboard_summary.golden │ │ │ ├── should_fetch_weekly_dashboard_summary.golden │ │ │ └── should_fetch_yearly_dashboard_summary.golden │ ├── TestRequirePermission_Basic │ │ ├── authorization_failed.golden │ │ ├── credentials_not_provided.golden │ │ ├── invalid_basic_credentials.golden │ │ ├── invalid_credentials.golden │ │ └── valid_credentials.golden │ ├── TestRequirePermission_Noop │ │ ├── authorization_failed.golden │ │ ├── credentials_not_provided.golden │ │ ├── invalid_credentials.golden │ │ └── valid_credentials.golden │ ├── Test_applicationHandler_DeleteApp │ │ ├── should_delete_app.golden │ │ └── should_fail_to_delete_app.golden │ ├── Test_applicationHandler_DeleteAppEndpoint │ │ ├── should_delete_app_endpoint.golden │ │ ├── should_error_for_endpoint_not_found.golden │ │ └── should_fail_to_delete_app_endpoint.golden │ ├── Test_applicationHandler_GetPaginatedApps │ │ └── valid_groups.golden │ ├── Test_fetchAuthConfig │ │ └── successful_auth_fetch.golden │ ├── Test_resendEventDelivery │ │ ├── invalid__resend_-_pending_endpoint.golden │ │ ├── invalid_resend_-_event_not_failed.golden │ │ ├── invalid_resend_-_event_successful.golden │ │ ├── valid_resend_-_previously_failed_-_active_endpoint.golden │ │ └── valid_resend_-_previously_failed_and_inactive_endpoint.golden │ └── Test_resendMessage │ │ ├── invalid__resend_-_pending_endpoint.golden │ │ ├── invalid_resend_-_event_not_failed.golden │ │ ├── invalid_resend_-_event_successful.golden │ │ ├── valid_resend_-_previously_failed_-_active_endpoint.golden │ │ └── valid_resend_-_previously_failed_and_inactive_endpoint.golden ├── testdb │ ├── filter.go │ └── seed.go ├── types │ └── types.go └── ui │ └── build │ └── go_test_stub.txt ├── auth ├── credential.go ├── realm.go ├── realm │ ├── file │ │ ├── file_realm.go │ │ └── file_realm_test.go │ ├── jwt │ │ ├── jwt.go │ │ ├── jwt_realm.go │ │ ├── jwt_realm_test.go │ │ └── jwt_test.go │ ├── native │ │ ├── native_realm.go │ │ └── native_realm_test.go │ ├── noop │ │ └── noop_realm.go │ └── portal │ │ └── portal_realm.go ├── realm_chain │ ├── realm_chain.go │ └── realm_chain_test.go └── role.go ├── cache ├── cache.go ├── memory │ ├── client.go │ └── client_test.go ├── noop │ └── noop.go └── redis │ ├── client.go │ └── client_test.go ├── cmd ├── agent │ └── agent.go ├── bootstrap │ └── bootstrap.go ├── config │ └── config.go ├── ff │ └── feature_flags.go ├── hooks │ └── hooks.go ├── ingest │ └── ingest.go ├── main.go ├── migrate │ └── migrate.go ├── openapi │ └── openapi.go ├── retry │ └── retry.go ├── server │ └── server.go ├── stream │ └── stream.go ├── utils │ ├── init_encryption.go │ ├── partition.go │ ├── revert_encryption.go │ ├── rotate_key.go │ └── utils.go ├── version │ └── version.go └── worker │ └── worker.go ├── config ├── algo │ └── algo.go ├── ca_cert.go ├── ca_cert_test.go ├── config.go ├── config_test.go ├── realm.go └── testdata │ ├── Config │ ├── empty-api-key-auth-group-name.json │ ├── empty-api-key.json │ ├── empty-redis-dsn.json │ ├── empty-ssl-cert-file.json │ ├── empty-ssl-key-file.json │ ├── no-port-convoy.json │ ├── too-large-max-response-size-convoy.json │ ├── unknown-strategy-type.json │ ├── valid-convoy-redis-cluster.json │ ├── valid-convoy.json │ └── zero-max-response-size-convoy.json │ └── Test_ConfigurationFromEnvironment │ └── convoy.json ├── configs ├── caddyfile ├── convoy.templ.json ├── docker-compose.templ.yml └── local │ ├── conf │ ├── .env │ └── userlists.txt │ ├── convoy.json │ ├── docker-compose.yml │ └── start.sh ├── const.go ├── convoy-logo.svg ├── convoy.env.example ├── convoy.go ├── convoy.json.example ├── database ├── database.go ├── hooks │ └── hooks.go ├── listener │ ├── endpoint_listener.go │ ├── event_delivery_listener.go │ └── project_listener.go ├── postgres │ ├── api_key.go │ ├── api_key_test.go │ ├── batch_retry.go │ ├── configuration.go │ ├── configuration_test.go │ ├── delivery_attempts.go │ ├── delivery_attempts_test.go │ ├── device.go │ ├── device_test.go │ ├── endpoint.go │ ├── endpoint_test.go │ ├── event.go │ ├── event_delivery.go │ ├── event_delivery_test.go │ ├── event_test.go │ ├── event_types.go │ ├── export.go │ ├── filter.go │ ├── job.go │ ├── job_test.go │ ├── meta_event.go │ ├── meta_event_test.go │ ├── organisation.go │ ├── organisation_invite.go │ ├── organisation_invite_test.go │ ├── organisation_member.go │ ├── organisation_member_test.go │ ├── organisation_test.go │ ├── portal_link.go │ ├── portal_link_test.go │ ├── postgres.go │ ├── postgres_collector.go │ ├── postgres_test.go │ ├── project.go │ ├── project_test.go │ ├── source.go │ ├── source_test.go │ ├── subscription.go │ ├── subscription_test.go │ ├── users.go │ └── users_test.go └── sqlite3 │ └── sqlite3.go ├── datastore ├── batch_retry.go ├── filter.go ├── filter_test.go ├── models.go ├── models_test.go ├── repository.go └── testdata │ ├── applications.yml │ └── organisations.yml ├── deploy ├── vm-deploy.sh └── vm-upgrade.sh ├── docker-compose.dep.yml ├── docker-compose.dev.yml ├── docs ├── docs.go ├── swagger.json ├── swagger.yaml └── v3 │ ├── openapi3.json │ └── openapi3.yaml ├── ee └── VERSION ├── generate.go ├── go.mod ├── go.sum ├── immune-test-files ├── test-app-endpoints.json ├── test-apps.json ├── test-groups.json └── test-push-events.json ├── internal ├── email │ ├── email.go │ ├── email_test.go │ └── templates │ │ ├── endpoint.update.html │ │ ├── organisation.invite.html │ │ ├── reset.password.html │ │ ├── twitter.source.html │ │ └── user.verify.email.html ├── notifications │ └── notifications.go ├── pkg │ ├── cli │ │ └── cli.go │ ├── crc │ │ ├── crc.go │ │ └── crc_test.go │ ├── dedup │ │ └── dedup.go │ ├── exporter │ │ └── exporter.go │ ├── fflag │ │ ├── fflag.go │ │ └── fflag_test.go │ ├── keys │ │ ├── encrypter_init.go │ │ ├── encrypter_revert.go │ │ ├── encrypter_rotate.go │ │ ├── hcpvault.go │ │ ├── hcpvault_test.go │ │ ├── keys.go │ │ ├── local.go │ │ └── vault.go │ ├── license │ │ ├── keygen │ │ │ ├── community.go │ │ │ ├── community_test.go │ │ │ ├── feature.go │ │ │ ├── keygen.go │ │ │ └── keygen_test.go │ │ ├── license.go │ │ └── noop │ │ │ └── noop.go │ ├── limiter │ │ ├── limiter.go │ │ ├── pg │ │ │ ├── client.go │ │ │ └── client_test.go │ │ └── redis │ │ │ ├── client.go │ │ │ └── client_test.go │ ├── loader │ │ ├── loader.go │ │ └── loader_test.go │ ├── memorystore │ │ ├── memorystore.go │ │ ├── row.go │ │ ├── table.go │ │ └── table_test.go │ ├── metrics │ │ ├── data_plane.go │ │ └── metrics.go │ ├── middleware │ │ └── middleware.go │ ├── migrator │ │ └── migrator.go │ ├── object-store │ │ ├── objectstore.go │ │ ├── onprem.go │ │ └── s3.go │ ├── openapi │ │ ├── converter.go │ │ ├── converter_test.go │ │ ├── testdata │ │ │ ├── test-2.0.yml │ │ │ ├── test-3.0.yml │ │ │ └── test-3.1.yml │ │ ├── validator.go │ │ └── validator_test.go │ ├── pubsub │ │ ├── amqp │ │ │ └── client.go │ │ ├── google │ │ │ └── client.go │ │ ├── ingest.go │ │ ├── kafka │ │ │ └── client.go │ │ ├── pubsub.go │ │ ├── pubsub_test.go │ │ ├── source_loader.go │ │ ├── source_loader_test.go │ │ ├── sqs │ │ │ └── client.go │ │ └── verifier.go │ ├── rdb │ │ └── rdb.go │ ├── retention │ │ └── retention.go │ ├── server │ │ └── server.go │ ├── smtp │ │ ├── smtp.go │ │ └── smtp_test.go │ ├── socket │ │ ├── client.go │ │ ├── client_test.go │ │ ├── handlers.go │ │ ├── handlers_test.go │ │ ├── server.go │ │ └── socket.go │ └── tracer │ │ ├── datadog.go │ │ ├── noop.go │ │ ├── otel.go │ │ ├── sentry.go │ │ └── tracer.go └── telemetry │ ├── mixpanel.go │ ├── posthog.go │ ├── telemetry.go │ └── tracker.go ├── loadtest ├── convoy.js └── setup.sh ├── mocks ├── cache.go ├── database.go ├── dedup.go ├── license.go ├── limiter.go ├── pubsub.go ├── queue.go ├── repository.go ├── searcher.go ├── smtp.go ├── socket.go ├── table.go └── tracer.go ├── net ├── dispatcher.go └── dispatcher_test.go ├── pkg ├── circuit_breaker │ ├── circuit_breaker.go │ ├── circuit_breaker_collector.go │ ├── circuit_breaker_manager.go │ ├── circuit_breaker_manager_test.go │ ├── circuit_breaker_test.go │ ├── config.go │ ├── config_test.go │ ├── store.go │ └── store_test.go ├── clock │ ├── clock.go │ └── clock_test.go ├── compare │ ├── compare.go │ └── compare_test.go ├── flatten │ ├── flat.go │ ├── flat_test.go │ ├── gh_event.json │ ├── gh_event_flat.json │ └── types.go ├── httpheader │ ├── httpheader.go │ └── httpheader_test.go ├── log │ ├── log.go │ └── std.go ├── models │ └── webhook.go ├── msgpack │ └── msgpack.go ├── signature │ ├── signature.go │ └── signature_test.go ├── transform │ ├── printer.go │ ├── transform.go │ └── transform_test.go ├── url │ ├── url_query.go │ └── url_query_test.go └── verifier │ ├── verifier.go │ └── verifier_test.go ├── plugin.go ├── plugins ├── add_headers_plugin.go └── add_headers_plugin_test.go ├── prometheus └── prometheus.yml ├── queue ├── queue.go ├── redis │ ├── client.go │ ├── client_test.go │ └── queue_collector.go └── testdata │ └── convoy_redis.json ├── release.Dockerfile ├── retrystrategies ├── default.go ├── default_test.go ├── exponentialBackoff.go ├── exponentialBackoff_test.go ├── retry.go └── retry_test.go ├── scripts ├── build.sh ├── integration-test.sh ├── release.sh ├── replica-set.sh └── ui.sh ├── services ├── activate_endpoint.go ├── batch_replay_event.go ├── batch_replay_event_test.go ├── batch_retry_event_delivery.go ├── batch_retry_event_delivery_test.go ├── cancel_invite.go ├── cancel_invite_test.go ├── create_api_key.go ├── create_api_key_test.go ├── create_broadcast_event.go ├── create_broadcast_event_test.go ├── create_configuration.go ├── create_configuration_test.go ├── create_dynamic_event.go ├── create_dynamic_event_test.go ├── create_endpoint.go ├── create_endpoint_api_key.go ├── create_endpoint_api_key_test.go ├── create_endpoint_test.go ├── create_fanout_event.go ├── create_fanout_event_test.go ├── create_meta_event.go ├── create_meta_event_test.go ├── create_organisation.go ├── create_organisation_test.go ├── create_personal_api_key.go ├── create_portal_link.go ├── create_portal_link_endpoint.go ├── create_portal_link_test.go ├── create_source.go ├── create_source_test.go ├── create_subscription.go ├── create_subscription_test.go ├── device_service.go ├── device_service_test.go ├── errors.go ├── expire_secret.go ├── expire_secret_test.go ├── find_user_by_invite_token.go ├── find_user_by_invite_token_test.go ├── force_resend_event_delivery.go ├── force_resend_event_delivery_test.go ├── generate_password_reset_token.go ├── generate_password_reset_token_test.go ├── import_openapi_spec.go ├── import_openapi_spec_test.go ├── invite_user.go ├── invite_user_test.go ├── login_sso.go ├── login_user.go ├── login_user_test.go ├── logout_user.go ├── logout_user_test.go ├── meta_event_service.go ├── meta_event_service_test.go ├── organisation_member_service.go ├── organisation_member_service_test.go ├── pause_endpoint.go ├── pause_endpoint_test.go ├── process_invite.go ├── process_invite_test.go ├── project_service.go ├── project_service_test.go ├── refresh_user_login_token.go ├── refresh_user_login_token_test.go ├── regenerate_project_api_key.go ├── regenerate_project_api_key_test.go ├── register_user.go ├── register_user_test.go ├── replay_event.go ├── replay_event_test.go ├── resend_invite.go ├── resend_invite_test.go ├── resend_user_email_verification.go ├── resend_user_email_verification_test.go ├── reset_password.go ├── reset_password_test.go ├── retry_event_delivery.go ├── retry_event_delivery_test.go ├── revoke_api_key.go ├── revoke_api_key_test.go ├── testdata │ ├── basic-config.json │ └── basic-convoy.json ├── update_api_key.go ├── update_api_key_test.go ├── update_configuration.go ├── update_configuration_test.go ├── update_endpoint.go ├── update_endpoint_test.go ├── update_organisation.go ├── update_organisation_test.go ├── update_portal_link.go ├── update_portal_link_test.go ├── update_source.go ├── update_source_test.go ├── update_subscription.go ├── update_subscription_test.go ├── update_user.go ├── update_user_password.go ├── update_user_password_test.go ├── update_user_test.go ├── verify_user_email.go └── verify_user_email_test.go ├── slim.Dockerfile ├── sql ├── 1677078479.sql ├── 1677770163.sql ├── 1679836136.sql ├── 1681821969.sql ├── 1684504109.sql ├── 1684884904.sql ├── 1684918027.sql ├── 1684929840.sql ├── 1685202737.sql ├── 1686048402.sql ├── 1686656160.sql ├── 1692024707.sql ├── 1692105853.sql ├── 1692699318.sql ├── 1693908172.sql ├── 1698074481.sql ├── 1698683940.sql ├── 1704372039.sql ├── 1705562731.sql ├── 1705575999.sql ├── 1708434555.sql ├── 1709568783.sql ├── 1709729972.sql ├── 1710685343.sql ├── 1710763531.sql ├── 1715118159.sql ├── 1715849591.sql ├── 1716983708.sql ├── 1717504961.sql ├── 1718819653.sql ├── 1719521272.sql ├── 1719521273.sql ├── 1721127636.sql ├── 1724236900.sql ├── 1724932863.sql ├── 1729585620.sql ├── 1729709223.sql ├── 1729941918.sql ├── 1730027360.sql ├── 1730719365.sql ├── 1733488138.sql ├── 1733518672.sql ├── 1735652782.sql ├── 1736807673.sql ├── 1739961493.sql ├── 1740483415.sql ├── 1742902597.sql ├── 1745514784.sql └── 1746876407.sql ├── test └── docker-compose.yml ├── testcon ├── direct_event_test.go ├── docker_e2e_integration_test.go ├── docker_e2e_integration_test_helper.go ├── fanout_event_test.go ├── manifest │ ├── counter.go │ ├── endpoint.go │ └── event.go └── testdata │ ├── convoy-docker.json │ ├── convoy-host.json │ └── docker-compose-test.yml ├── testdata └── test-2.0.yml ├── type.go ├── util ├── crypto.go ├── crypto_test.go ├── db.go ├── endpoint.go ├── endpoint_test.go ├── header.go ├── json.go ├── name.go ├── response.go ├── slice.go ├── strings.go ├── strings_test.go └── validator.go ├── v3gen └── main.go ├── web └── ui │ └── dashboard │ ├── .browserslistrc │ ├── .editorconfig │ ├── .gitignore │ ├── .prettierrc │ ├── .storybook │ ├── main.js │ ├── preview.js │ ├── tsconfig.json │ └── typings.d.ts │ ├── README.md │ ├── angular.json │ ├── documentation.json │ ├── karma.conf.js │ ├── package.json │ ├── post-build-css.js │ ├── purgecss.config.js │ ├── src │ ├── app │ │ ├── app-routing.module.ts │ │ ├── app.component.html │ │ ├── app.component.scss │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── components │ │ │ ├── badge │ │ │ │ ├── badge.component.html │ │ │ │ ├── badge.component.scss │ │ │ │ ├── badge.component.spec.ts │ │ │ │ └── badge.component.ts │ │ │ ├── button │ │ │ │ ├── button.component.html │ │ │ │ ├── button.component.scss │ │ │ │ ├── button.component.spec.ts │ │ │ │ └── button.component.ts │ │ │ ├── card │ │ │ │ ├── card.component.spec.ts │ │ │ │ └── card.component.ts │ │ │ ├── chart │ │ │ │ ├── chart.component.html │ │ │ │ ├── chart.component.scss │ │ │ │ ├── chart.component.spec.ts │ │ │ │ └── chart.component.ts │ │ │ ├── components.module.ts │ │ │ ├── copy-button │ │ │ │ ├── copy-button.component.html │ │ │ │ ├── copy-button.component.scss │ │ │ │ ├── copy-button.component.spec.ts │ │ │ │ └── copy-button.component.ts │ │ │ ├── date-picker │ │ │ │ ├── date-picker.component.html │ │ │ │ ├── date-picker.component.scss │ │ │ │ ├── date-picker.component.spec.ts │ │ │ │ └── date-picker.component.ts │ │ │ ├── dialog │ │ │ │ ├── dialog.directive.spec.ts │ │ │ │ └── dialog.directive.ts │ │ │ ├── dropdown-container │ │ │ │ ├── dropdown-container.component.html │ │ │ │ ├── dropdown-container.component.scss │ │ │ │ ├── dropdown-container.component.spec.ts │ │ │ │ └── dropdown-container.component.ts │ │ │ ├── dropdown │ │ │ │ ├── dropdown.component.html │ │ │ │ ├── dropdown.component.scss │ │ │ │ ├── dropdown.component.spec.ts │ │ │ │ └── dropdown.component.ts │ │ │ ├── empty-state │ │ │ │ ├── empty-state.component.html │ │ │ │ ├── empty-state.component.scss │ │ │ │ ├── empty-state.component.spec.ts │ │ │ │ └── empty-state.component.ts │ │ │ ├── file-input │ │ │ │ ├── file-input.component.html │ │ │ │ ├── file-input.component.scss │ │ │ │ ├── file-input.component.spec.ts │ │ │ │ └── file-input.component.ts │ │ │ ├── form-loader │ │ │ │ ├── form-loader.component.spec.ts │ │ │ │ └── form-loader.component.ts │ │ │ ├── github-star │ │ │ │ ├── github-star.component.html │ │ │ │ ├── github-star.component.scss │ │ │ │ ├── github-star.component.spec.ts │ │ │ │ └── github-star.component.ts │ │ │ ├── input │ │ │ │ ├── input.component.scss │ │ │ │ ├── input.component.spec.ts │ │ │ │ └── input.component.ts │ │ │ ├── list-item │ │ │ │ ├── list-item.component.spec.ts │ │ │ │ └── list-item.component.ts │ │ │ ├── multi-input │ │ │ │ ├── multi-input.component.html │ │ │ │ ├── multi-input.component.scss │ │ │ │ ├── multi-input.component.spec.ts │ │ │ │ └── multi-input.component.ts │ │ │ ├── notification-modal │ │ │ │ ├── notification-modal.component.html │ │ │ │ ├── notification-modal.component.scss │ │ │ │ ├── notification-modal.component.spec.ts │ │ │ │ └── notification-modal.component.ts │ │ │ ├── notification │ │ │ │ ├── notification.component.html │ │ │ │ ├── notification.component.scss │ │ │ │ ├── notification.component.spec.ts │ │ │ │ └── notification.component.ts │ │ │ ├── overlay │ │ │ │ ├── overlay.directive.spec.ts │ │ │ │ └── overlay.directive.ts │ │ │ ├── page │ │ │ │ ├── page.component.spec.ts │ │ │ │ └── page.component.ts │ │ │ ├── radio │ │ │ │ ├── radio.component.html │ │ │ │ ├── radio.component.scss │ │ │ │ ├── radio.component.spec.ts │ │ │ │ └── radio.component.ts │ │ │ ├── select │ │ │ │ ├── select.component.html │ │ │ │ ├── select.component.scss │ │ │ │ ├── select.component.spec.ts │ │ │ │ └── select.component.ts │ │ │ ├── skeleton-loader │ │ │ │ ├── skeleton-loader.component.html │ │ │ │ ├── skeleton-loader.component.scss │ │ │ │ ├── skeleton-loader.component.spec.ts │ │ │ │ └── skeleton-loader.component.ts │ │ │ ├── table │ │ │ │ ├── table.component.spec.ts │ │ │ │ └── table.component.ts │ │ │ ├── tag │ │ │ │ ├── tag.component.spec.ts │ │ │ │ └── tag.component.ts │ │ │ ├── time-picker │ │ │ │ ├── time-picker.component.html │ │ │ │ ├── time-picker.component.scss │ │ │ │ ├── time-picker.component.spec.ts │ │ │ │ └── time-picker.component.ts │ │ │ ├── toggle │ │ │ │ ├── toggle.component.html │ │ │ │ ├── toggle.component.scss │ │ │ │ ├── toggle.component.spec.ts │ │ │ │ └── toggle.component.ts │ │ │ └── tooltip │ │ │ │ ├── tooltip.component.html │ │ │ │ ├── tooltip.component.scss │ │ │ │ ├── tooltip.component.spec.ts │ │ │ │ └── tooltip.component.ts │ │ ├── guards │ │ │ └── iframe │ │ │ │ ├── iframe.guard.spec.ts │ │ │ │ └── iframe.guard.ts │ │ ├── interceptor │ │ │ ├── http.interceptor.spec.ts │ │ │ └── http.interceptor.ts │ │ ├── models │ │ │ ├── device.model.ts │ │ │ ├── endpoint.model.ts │ │ │ ├── event.model.ts │ │ │ ├── filter.model.ts │ │ │ ├── flipt.model.ts │ │ │ ├── global.model.ts │ │ │ ├── organisation.model.ts │ │ │ ├── project.model.ts │ │ │ ├── source.model.ts │ │ │ ├── subscription.ts │ │ │ └── user.model.ts │ │ ├── pipes │ │ │ ├── formatSeconds │ │ │ │ ├── format-seconds.pipe.spec.ts │ │ │ │ └── format-seconds.pipe.ts │ │ │ ├── role │ │ │ │ ├── role.pipe.spec.ts │ │ │ │ └── role.pipe.ts │ │ │ ├── source-value │ │ │ │ ├── source-value.module.ts │ │ │ │ ├── source-value.pipe.spec.ts │ │ │ │ └── source-value.pipe.ts │ │ │ └── status-color │ │ │ │ ├── status-color.module.ts │ │ │ │ ├── status-color.pipe.spec.ts │ │ │ │ └── status-color.pipe.ts │ │ ├── portal │ │ │ ├── create-portal-endpoint │ │ │ │ ├── create-portal-endpoint.component.html │ │ │ │ ├── create-portal-endpoint.component.scss │ │ │ │ └── create-portal-endpoint.component.ts │ │ │ ├── create-portal-transform-function │ │ │ │ ├── create-portal-transform-function.component.html │ │ │ │ ├── create-portal-transform-function.component.scss │ │ │ │ ├── create-portal-transform-function.component.spec.ts │ │ │ │ └── create-portal-transform-function.component.ts │ │ │ ├── endpoints │ │ │ │ ├── endpoints.component.html │ │ │ │ ├── endpoints.component.scss │ │ │ │ ├── endpoints.component.spec.ts │ │ │ │ └── endpoints.component.ts │ │ │ ├── event-catalog │ │ │ │ ├── event-catalog.component.html │ │ │ │ ├── event-catalog.component.scss │ │ │ │ ├── event-catalog.component.spec.ts │ │ │ │ └── event-catalog.component.ts │ │ │ ├── event-deliveries │ │ │ │ ├── event-deliveries.component.html │ │ │ │ ├── event-deliveries.component.scss │ │ │ │ ├── event-deliveries.component.spec.ts │ │ │ │ └── event-deliveries.component.ts │ │ │ ├── event-delivery │ │ │ │ ├── event-delivery.component.html │ │ │ │ ├── event-delivery.component.scss │ │ │ │ ├── event-delivery.component.spec.ts │ │ │ │ └── event-delivery.component.ts │ │ │ ├── portal.component.html │ │ │ ├── portal.component.scss │ │ │ ├── portal.component.spec.ts │ │ │ ├── portal.component.ts │ │ │ ├── portal.service.spec.ts │ │ │ ├── portal.service.ts │ │ │ └── subscriptions │ │ │ │ ├── subscriptions.component.html │ │ │ │ ├── subscriptions.component.scss │ │ │ │ ├── subscriptions.component.spec.ts │ │ │ │ └── subscriptions.component.ts │ │ ├── private │ │ │ ├── components │ │ │ │ ├── config-button │ │ │ │ │ ├── config-button.component.html │ │ │ │ │ ├── config-button.component.spec.ts │ │ │ │ │ └── config-button.component.ts │ │ │ │ ├── create-endpoint │ │ │ │ │ ├── create-endpoint.component.html │ │ │ │ │ ├── create-endpoint.component.scss │ │ │ │ │ ├── create-endpoint.component.spec.ts │ │ │ │ │ ├── create-endpoint.component.ts │ │ │ │ │ ├── create-endpoint.service.spec.ts │ │ │ │ │ └── create-endpoint.service.ts │ │ │ │ ├── create-portal-link │ │ │ │ │ ├── create-portal-link.component.html │ │ │ │ │ ├── create-portal-link.component.scss │ │ │ │ │ ├── create-portal-link.component.spec.ts │ │ │ │ │ ├── create-portal-link.component.ts │ │ │ │ │ ├── create-portal-link.service.spec.ts │ │ │ │ │ └── create-portal-link.service.ts │ │ │ │ ├── create-project-component │ │ │ │ │ ├── create-project-component.component.html │ │ │ │ │ ├── create-project-component.component.scss │ │ │ │ │ ├── create-project-component.component.spec.ts │ │ │ │ │ ├── create-project-component.component.ts │ │ │ │ │ ├── create-project-component.module.ts │ │ │ │ │ ├── create-project-component.service.spec.ts │ │ │ │ │ └── create-project-component.service.ts │ │ │ │ ├── create-source │ │ │ │ │ ├── create-source.component.html │ │ │ │ │ ├── create-source.component.scss │ │ │ │ │ ├── create-source.component.spec.ts │ │ │ │ │ ├── create-source.component.ts │ │ │ │ │ ├── create-source.module.ts │ │ │ │ │ ├── create-source.service.spec.ts │ │ │ │ │ ├── create-source.service.ts │ │ │ │ │ └── source-url │ │ │ │ │ │ ├── source-url.component.html │ │ │ │ │ │ ├── source-url.component.spec.ts │ │ │ │ │ │ └── source-url.component.ts │ │ │ │ ├── create-subscription-filter │ │ │ │ │ ├── create-subscription-filter.component.html │ │ │ │ │ ├── create-subscription-filter.component.scss │ │ │ │ │ ├── create-subscription-filter.component.spec.ts │ │ │ │ │ └── create-subscription-filter.component.ts │ │ │ │ ├── create-subscription │ │ │ │ │ ├── create-subscription.component.html │ │ │ │ │ ├── create-subscription.component.scss │ │ │ │ │ ├── create-subscription.component.spec.ts │ │ │ │ │ ├── create-subscription.component.ts │ │ │ │ │ ├── create-subscription.module.ts │ │ │ │ │ ├── create-subscription.service.spec.ts │ │ │ │ │ ├── create-subscription.service.ts │ │ │ │ │ └── filter.service.ts │ │ │ │ ├── create-transform-function │ │ │ │ │ ├── create-transform-function.component.html │ │ │ │ │ ├── create-transform-function.component.scss │ │ │ │ │ ├── create-transform-function.component.spec.ts │ │ │ │ │ └── create-transform-function.component.ts │ │ │ │ ├── delete-modal │ │ │ │ │ ├── delete-modal.component.html │ │ │ │ │ ├── delete-modal.component.scss │ │ │ │ │ ├── delete-modal.component.spec.ts │ │ │ │ │ └── delete-modal.component.ts │ │ │ │ ├── endpoints-filter │ │ │ │ │ ├── endpoints-filter.component.html │ │ │ │ │ ├── endpoints-filter.component.spec.ts │ │ │ │ │ └── endpoints-filter.component.ts │ │ │ │ ├── enterprise │ │ │ │ │ ├── enterprise.directive.spec.ts │ │ │ │ │ └── enterprise.directive.ts │ │ │ │ ├── event-delivery-filter │ │ │ │ │ ├── event-delivery-filter.component.html │ │ │ │ │ ├── event-delivery-filter.component.scss │ │ │ │ │ ├── event-delivery-filter.component.spec.ts │ │ │ │ │ └── event-delivery-filter.component.ts │ │ │ │ ├── loader │ │ │ │ │ ├── loader.component.html │ │ │ │ │ ├── loader.component.scss │ │ │ │ │ ├── loader.component.spec.ts │ │ │ │ │ ├── loader.component.ts │ │ │ │ │ └── loader.module.ts │ │ │ │ ├── monaco │ │ │ │ │ ├── monaco.component.html │ │ │ │ │ ├── monaco.component.scss │ │ │ │ │ ├── monaco.component.spec.ts │ │ │ │ │ ├── monaco.component.ts │ │ │ │ │ ├── monaco.service.spec.ts │ │ │ │ │ └── monaco.service.ts │ │ │ │ ├── pagination │ │ │ │ │ ├── pagination.component.html │ │ │ │ │ ├── pagination.component.scss │ │ │ │ │ ├── pagination.component.spec.ts │ │ │ │ │ └── pagination.component.ts │ │ │ │ ├── permission │ │ │ │ │ ├── permission.directive.spec.ts │ │ │ │ │ └── permission.directive.ts │ │ │ │ ├── prism │ │ │ │ │ ├── prism.component.html │ │ │ │ │ ├── prism.component.scss │ │ │ │ │ ├── prism.component.spec.ts │ │ │ │ │ ├── prism.component.ts │ │ │ │ │ └── prism.module.ts │ │ │ │ ├── sdk-documentation │ │ │ │ │ ├── sdk-documentation.component.html │ │ │ │ │ ├── sdk-documentation.component.scss │ │ │ │ │ ├── sdk-documentation.component.spec.ts │ │ │ │ │ └── sdk-documentation.component.ts │ │ │ │ ├── table-loader │ │ │ │ │ ├── table-loader.component.html │ │ │ │ │ ├── table-loader.component.scss │ │ │ │ │ ├── table-loader.component.spec.ts │ │ │ │ │ ├── table-loader.component.ts │ │ │ │ │ └── table-loader.module.ts │ │ │ │ ├── token-modal │ │ │ │ │ ├── token-modal.component.html │ │ │ │ │ ├── token-modal.component.scss │ │ │ │ │ ├── token-modal.component.spec.ts │ │ │ │ │ └── token-modal.component.ts │ │ │ │ └── verify-email │ │ │ │ │ ├── verify-email.component.html │ │ │ │ │ ├── verify-email.component.scss │ │ │ │ │ ├── verify-email.component.spec.ts │ │ │ │ │ ├── verify-email.component.ts │ │ │ │ │ ├── verify-email.service.spec.ts │ │ │ │ │ └── verify-email.service.ts │ │ │ ├── pages │ │ │ │ ├── account │ │ │ │ │ ├── account.component.html │ │ │ │ │ ├── account.component.scss │ │ │ │ │ ├── account.component.spec.ts │ │ │ │ │ ├── account.component.ts │ │ │ │ │ ├── account.module.ts │ │ │ │ │ ├── account.service.spec.ts │ │ │ │ │ ├── account.service.ts │ │ │ │ │ ├── personal-settings │ │ │ │ │ │ ├── personal-settings.component.html │ │ │ │ │ │ ├── personal-settings.component.scss │ │ │ │ │ │ ├── personal-settings.component.spec.ts │ │ │ │ │ │ └── personal-settings.component.ts │ │ │ │ │ ├── profile-settings │ │ │ │ │ │ ├── profile-settings.component.html │ │ │ │ │ │ ├── profile-settings.component.scss │ │ │ │ │ │ ├── profile-settings.component.spec.ts │ │ │ │ │ │ └── profile-settings.component.ts │ │ │ │ │ └── security-settings │ │ │ │ │ │ ├── security-settings.component.html │ │ │ │ │ │ ├── security-settings.component.scss │ │ │ │ │ │ ├── security-settings.component.spec.ts │ │ │ │ │ │ └── security-settings.component.ts │ │ │ │ ├── app │ │ │ │ │ ├── app.component.html │ │ │ │ │ ├── app.component.scss │ │ │ │ │ ├── app.component.spec.ts │ │ │ │ │ ├── app.component.ts │ │ │ │ │ └── app.module.ts │ │ │ │ ├── create-project │ │ │ │ │ ├── create-project.component.html │ │ │ │ │ ├── create-project.component.scss │ │ │ │ │ ├── create-project.component.spec.ts │ │ │ │ │ ├── create-project.component.ts │ │ │ │ │ └── create-project.module.ts │ │ │ │ ├── dashboard │ │ │ │ │ ├── dashboard.component.html │ │ │ │ │ ├── dashboard.component.scss │ │ │ │ │ ├── dashboard.component.spec.ts │ │ │ │ │ ├── dashboard.component.ts │ │ │ │ │ └── dashboard.module.ts │ │ │ │ ├── onboarding │ │ │ │ │ ├── onboarding.component.html │ │ │ │ │ ├── onboarding.component.scss │ │ │ │ │ ├── onboarding.component.spec.ts │ │ │ │ │ └── onboarding.component.ts │ │ │ │ ├── project │ │ │ │ │ ├── endpoints │ │ │ │ │ │ ├── endpoint-secret │ │ │ │ │ │ │ ├── endpoint-secret.component.html │ │ │ │ │ │ │ ├── endpoint-secret.component.scss │ │ │ │ │ │ │ ├── endpoint-secret.component.spec.ts │ │ │ │ │ │ │ └── endpoint-secret.component.ts │ │ │ │ │ │ ├── endpoints.component.html │ │ │ │ │ │ ├── endpoints.component.scss │ │ │ │ │ │ ├── endpoints.component.spec.ts │ │ │ │ │ │ ├── endpoints.component.ts │ │ │ │ │ │ ├── endpoints.service.spec.ts │ │ │ │ │ │ └── endpoints.service.ts │ │ │ │ │ ├── event-logs │ │ │ │ │ │ ├── event-logs.component.html │ │ │ │ │ │ ├── event-logs.component.scss │ │ │ │ │ │ ├── event-logs.component.spec.ts │ │ │ │ │ │ ├── event-logs.component.ts │ │ │ │ │ │ ├── event-logs.service.spec.ts │ │ │ │ │ │ └── event-logs.service.ts │ │ │ │ │ ├── events │ │ │ │ │ │ ├── event-deliveries │ │ │ │ │ │ │ ├── event-deliveries.component.html │ │ │ │ │ │ │ ├── event-deliveries.component.scss │ │ │ │ │ │ │ ├── event-deliveries.component.spec.ts │ │ │ │ │ │ │ ├── event-deliveries.component.ts │ │ │ │ │ │ │ └── event-deliveries.module.ts │ │ │ │ │ │ ├── event-delivery-details-page │ │ │ │ │ │ │ ├── event-delivery-details-page.component.html │ │ │ │ │ │ │ ├── event-delivery-details-page.component.scss │ │ │ │ │ │ │ ├── event-delivery-details-page.component.spec.ts │ │ │ │ │ │ │ ├── event-delivery-details-page.component.ts │ │ │ │ │ │ │ └── event-delivery-details-page.module.ts │ │ │ │ │ │ ├── event-delivery-details │ │ │ │ │ │ │ ├── event-delivery-details.component.html │ │ │ │ │ │ │ ├── event-delivery-details.component.scss │ │ │ │ │ │ │ ├── event-delivery-details.component.spec.ts │ │ │ │ │ │ │ ├── event-delivery-details.component.ts │ │ │ │ │ │ │ ├── event-delivery-details.module.ts │ │ │ │ │ │ │ ├── event-delivery-details.service.spec.ts │ │ │ │ │ │ │ └── event-delivery-details.service.ts │ │ │ │ │ │ ├── events.component.html │ │ │ │ │ │ ├── events.component.scss │ │ │ │ │ │ ├── events.component.spec.ts │ │ │ │ │ │ ├── events.component.ts │ │ │ │ │ │ ├── events.module.ts │ │ │ │ │ │ ├── events.service.spec.ts │ │ │ │ │ │ └── events.service.ts │ │ │ │ │ ├── meta-events │ │ │ │ │ │ ├── meta-events.component.html │ │ │ │ │ │ ├── meta-events.component.scss │ │ │ │ │ │ ├── meta-events.component.spec.ts │ │ │ │ │ │ ├── meta-events.component.ts │ │ │ │ │ │ ├── meta-events.service.spec.ts │ │ │ │ │ │ └── meta-events.service.ts │ │ │ │ │ ├── portal-links │ │ │ │ │ │ ├── portal-links.component.html │ │ │ │ │ │ ├── portal-links.component.scss │ │ │ │ │ │ ├── portal-links.component.spec.ts │ │ │ │ │ │ ├── portal-links.component.ts │ │ │ │ │ │ ├── portal-links.service.spec.ts │ │ │ │ │ │ └── portal-links.service.ts │ │ │ │ │ ├── project.component.html │ │ │ │ │ ├── project.component.scss │ │ │ │ │ ├── project.component.spec.ts │ │ │ │ │ ├── project.component.ts │ │ │ │ │ ├── project.module.ts │ │ │ │ │ ├── project.service.ts │ │ │ │ │ ├── settings │ │ │ │ │ │ ├── settings.component.html │ │ │ │ │ │ ├── settings.component.scss │ │ │ │ │ │ ├── settings.component.spec.ts │ │ │ │ │ │ ├── settings.component.ts │ │ │ │ │ │ └── settings.module.ts │ │ │ │ │ ├── sources │ │ │ │ │ │ ├── sources.component.html │ │ │ │ │ │ ├── sources.component.scss │ │ │ │ │ │ ├── sources.component.spec.ts │ │ │ │ │ │ ├── sources.component.ts │ │ │ │ │ │ ├── sources.module.ts │ │ │ │ │ │ ├── sources.service.spec.ts │ │ │ │ │ │ └── sources.service.ts │ │ │ │ │ └── subscriptions │ │ │ │ │ │ ├── subscriptions.component.html │ │ │ │ │ │ ├── subscriptions.component.scss │ │ │ │ │ │ ├── subscriptions.component.spec.ts │ │ │ │ │ │ ├── subscriptions.component.ts │ │ │ │ │ │ └── subscriptions.module.ts │ │ │ │ ├── projects │ │ │ │ │ ├── projects.component.html │ │ │ │ │ ├── projects.component.scss │ │ │ │ │ ├── projects.component.spec.ts │ │ │ │ │ ├── projects.component.ts │ │ │ │ │ └── projects.module.ts │ │ │ │ ├── settings │ │ │ │ │ ├── configurations │ │ │ │ │ │ ├── configurations.component.html │ │ │ │ │ │ ├── configurations.component.scss │ │ │ │ │ │ ├── configurations.component.spec.ts │ │ │ │ │ │ └── configurations.component.ts │ │ │ │ │ ├── organisation-settings │ │ │ │ │ │ ├── organisation-settings.component.html │ │ │ │ │ │ ├── organisation-settings.component.scss │ │ │ │ │ │ ├── organisation-settings.component.spec.ts │ │ │ │ │ │ └── organisation-settings.component.ts │ │ │ │ │ ├── settings.component.html │ │ │ │ │ ├── settings.component.scss │ │ │ │ │ ├── settings.component.spec.ts │ │ │ │ │ ├── settings.component.ts │ │ │ │ │ ├── settings.module.ts │ │ │ │ │ ├── settings.service.spec.ts │ │ │ │ │ ├── settings.service.ts │ │ │ │ │ └── teams │ │ │ │ │ │ ├── teams.component.html │ │ │ │ │ │ ├── teams.component.scss │ │ │ │ │ │ ├── teams.component.spec.ts │ │ │ │ │ │ ├── teams.component.ts │ │ │ │ │ │ ├── teams.module.ts │ │ │ │ │ │ ├── teams.service.spec.ts │ │ │ │ │ │ └── teams.service.ts │ │ │ │ └── setup-project │ │ │ │ │ ├── setup-project.component.html │ │ │ │ │ ├── setup-project.component.scss │ │ │ │ │ ├── setup-project.component.spec.ts │ │ │ │ │ └── setup-project.component.ts │ │ │ ├── private-routers.ts │ │ │ ├── private-routing.ee.module.ts │ │ │ ├── private-routing.module.ts │ │ │ ├── private.component.html │ │ │ ├── private.component.scss │ │ │ ├── private.component.spec.ts │ │ │ ├── private.component.ts │ │ │ ├── private.module.ts │ │ │ └── private.service.ts │ │ ├── public │ │ │ ├── accept-invite │ │ │ │ ├── accept-invite.component.html │ │ │ │ ├── accept-invite.component.scss │ │ │ │ ├── accept-invite.component.spec.ts │ │ │ │ ├── accept-invite.component.ts │ │ │ │ ├── accept-invite.service.spec.ts │ │ │ │ └── accept-invite.service.ts │ │ │ ├── forgot-password │ │ │ │ ├── forgot-password.component.html │ │ │ │ ├── forgot-password.component.scss │ │ │ │ ├── forgot-password.component.spec.ts │ │ │ │ ├── forgot-password.component.ts │ │ │ │ ├── forgot-password.service.spec.ts │ │ │ │ └── forgot-password.service.ts │ │ │ ├── login │ │ │ │ ├── login.component.html │ │ │ │ ├── login.component.scss │ │ │ │ ├── login.component.spec.ts │ │ │ │ ├── login.component.ts │ │ │ │ ├── login.service.spec.ts │ │ │ │ └── login.service.ts │ │ │ ├── public.component.html │ │ │ ├── public.component.scss │ │ │ ├── public.component.spec.ts │ │ │ ├── public.component.ts │ │ │ ├── public.module.ts │ │ │ ├── reset-password │ │ │ │ ├── reset-password.component.html │ │ │ │ ├── reset-password.component.scss │ │ │ │ ├── reset-password.component.spec.ts │ │ │ │ ├── reset-password.component.ts │ │ │ │ ├── reset-password.service.spec.ts │ │ │ │ └── reset-password.service.ts │ │ │ ├── saml │ │ │ │ ├── saml.component.html │ │ │ │ ├── saml.component.scss │ │ │ │ ├── saml.component.spec.ts │ │ │ │ ├── saml.component.ts │ │ │ │ ├── saml.service.spec.ts │ │ │ │ └── saml.service.ts │ │ │ ├── signup │ │ │ │ ├── signup.component.html │ │ │ │ ├── signup.component.scss │ │ │ │ ├── signup.component.spec.ts │ │ │ │ ├── signup.component.ts │ │ │ │ ├── signup.service.spec.ts │ │ │ │ └── signup.service.ts │ │ │ └── verify-email │ │ │ │ ├── verify-email.component.html │ │ │ │ ├── verify-email.component.scss │ │ │ │ ├── verify-email.component.spec.ts │ │ │ │ ├── verify-email.component.ts │ │ │ │ ├── verify-email.service.spec.ts │ │ │ │ └── verify-email.service.ts │ │ └── services │ │ │ ├── general │ │ │ ├── general.service.spec.ts │ │ │ └── general.service.ts │ │ │ ├── http │ │ │ ├── http.helper.service.ts │ │ │ ├── http.service.spec.ts │ │ │ └── http.service.ts │ │ │ ├── hubspot │ │ │ ├── hubspot.service.spec.ts │ │ │ └── hubspot.service.ts │ │ │ ├── licenses │ │ │ ├── licenses.service.spec.ts │ │ │ └── licenses.service.ts │ │ │ └── rbac │ │ │ ├── rbac.service.spec.ts │ │ │ └── rbac.service.ts │ ├── assets │ │ ├── .gitkeep │ │ ├── fonts │ │ │ ├── Menlo-Regular.woff │ │ │ └── inter │ │ │ │ ├── UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7W0Q5n-wU.woff2 │ │ │ │ ├── UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7W0Q5nw.woff2 │ │ │ │ ├── UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7W0Q5n-wU.woff2 │ │ │ │ ├── UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7W0Q5n-wU.woff2 │ │ │ │ ├── UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7W0Q5n-wU.woff2 │ │ │ │ ├── UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7W0Q5n-wU.woff2 │ │ │ │ └── UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7W0Q5n-wU.woff2 │ │ └── img │ │ │ ├── Checkbox.svg │ │ │ ├── Loader.png │ │ │ ├── Pattern.svg │ │ │ ├── add-circlar-icon.svg │ │ │ ├── add-icon.svg │ │ │ ├── amqp.png │ │ │ ├── angle-arrow-down.svg │ │ │ ├── angle-arrow-left.svg │ │ │ ├── angle-arrow-right-primary.svg │ │ │ ├── angle-arrow-right.svg │ │ │ ├── angle-arrow-up.svg │ │ │ ├── angle-down.svg │ │ │ ├── apps-icon-grey.svg │ │ │ ├── apps-icon-transparent.svg │ │ │ ├── apps-icon.svg │ │ │ ├── arrow-down-icon.svg │ │ │ ├── arrow-left-primary.svg │ │ │ ├── arrow-up-right.svg │ │ │ ├── button-loader.gif │ │ │ ├── calendar-icon.svg │ │ │ ├── chart-icon.svg │ │ │ ├── chart.svg │ │ │ ├── check-icon-primary.svg │ │ │ ├── checkbox-icon.svg │ │ │ ├── checkmark.svg │ │ │ ├── clock.svg │ │ │ ├── close icon.svg │ │ │ ├── close-icon-black.svg │ │ │ ├── close-icon-grey.svg │ │ │ ├── close-icon.svg │ │ │ ├── copy-icon.svg │ │ │ ├── copy.svg │ │ │ ├── doc-icon-primary.svg │ │ │ ├── download.png │ │ │ ├── empty-state-img.svg │ │ │ ├── empty-state.svg │ │ │ ├── endpoint-discord-icon.svg │ │ │ ├── endpoint-hubspot-icon.svg │ │ │ ├── endpoint-slack-icon.svg │ │ │ ├── endpoint-telegram-icon.svg │ │ │ ├── endpoint-webhook-icon.svg │ │ │ ├── endpoint-zapier-icon.svg │ │ │ ├── endpoints-icon.svg │ │ │ ├── enter-icon.png │ │ │ ├── error-icon.svg │ │ │ ├── events-empty-state-image.svg │ │ │ ├── events-log-empty-state.png │ │ │ ├── file.png │ │ │ ├── filter-icon.svg │ │ │ ├── filter.gif │ │ │ ├── forgot-password.svg │ │ │ ├── github.png │ │ │ ├── go.png │ │ │ ├── google.png │ │ │ ├── group-empty-img.svg │ │ │ ├── ideas.svg │ │ │ ├── info-icon.svg │ │ │ ├── inherit-icon.svg │ │ │ ├── input-error-icon.svg │ │ │ ├── input-valid-icon.svg │ │ │ ├── js.png │ │ │ ├── kafka.png │ │ │ ├── link-icon.svg │ │ │ ├── loader.gif │ │ │ ├── lock.svg │ │ │ ├── logo.svg │ │ │ ├── message-icon-transparent.svg │ │ │ ├── message-icon.svg │ │ │ ├── modal-close-icon.svg │ │ │ ├── more-horizontal.svg │ │ │ ├── more-icon-vertical.svg │ │ │ ├── nav-bar-more-primary.svg │ │ │ ├── new-empty-state.png │ │ │ ├── new-success.gif │ │ │ ├── no-group.svg │ │ │ ├── org-empty-img.svg │ │ │ ├── organisation-icon.svg │ │ │ ├── organizations-empty-state.svg │ │ │ ├── page-loader.gif │ │ │ ├── password-invisible-icon.svg │ │ │ ├── password-reset-success-img.svg │ │ │ ├── password-visible-icon.svg │ │ │ ├── php.png │ │ │ ├── portal-link-empty-state.png │ │ │ ├── primary-info-icon.svg │ │ │ ├── public-layout.png │ │ │ ├── python.png │ │ │ ├── refresh-icon-2.svg │ │ │ ├── refresh-icon-force.svg │ │ │ ├── refresh-icon-primary.svg │ │ │ ├── refresh-icon.svg │ │ │ ├── retry-icon.svg │ │ │ ├── rotate-icon.svg │ │ │ ├── ruby.png │ │ │ ├── search-icon.svg │ │ │ ├── setting.svg │ │ │ ├── shopify.png │ │ │ ├── small-info-icon.svg │ │ │ ├── sources-empty-state.png │ │ │ ├── sqs.png │ │ │ ├── square-check.svg │ │ │ ├── status-filter-icon.svg │ │ │ ├── subscriptions-empty-state.png │ │ │ ├── success-icon.svg │ │ │ ├── success.gif │ │ │ ├── success.png │ │ │ ├── svg │ │ │ ├── help-circle.svg │ │ │ ├── lock-open.svg │ │ │ ├── lock_open.svg │ │ │ ├── new-check-icon.svg │ │ │ ├── page-locked.svg │ │ │ ├── plus-icon.svg │ │ │ ├── project-info.svg │ │ │ ├── projects.svg │ │ │ └── retention-icon.svg │ │ │ ├── team-empty-img.svg │ │ │ ├── teams-empty-state.png │ │ │ ├── time-icon.svg │ │ │ ├── trash-icon.svg │ │ │ ├── twitter.png │ │ │ ├── user-icon.svg │ │ │ ├── view-events-icon.svg │ │ │ ├── view-icon.svg │ │ │ ├── warning-icon.svg │ │ │ ├── warning.gif │ │ │ └── white-logo.svg │ ├── content │ │ └── sdks │ │ │ ├── go │ │ │ ├── Add Endpoint.md │ │ │ ├── Installation.md │ │ │ └── Send Event.md │ │ │ ├── js │ │ │ ├── Add Endpoint.md │ │ │ ├── Installation.md │ │ │ └── Send Event.md │ │ │ ├── php │ │ │ ├── Add Endpoint.md │ │ │ ├── Installation.md │ │ │ └── Send Event.md │ │ │ ├── python │ │ │ ├── Add Endpoint.md │ │ │ ├── Installation.md │ │ │ └── Send Event.md │ │ │ └── ruby │ │ │ ├── Add Endpoint.md │ │ │ ├── Installation.md │ │ │ └── Send Event.md │ ├── environments │ │ ├── environment.ee.ts │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── scss │ │ ├── _font.scss │ │ ├── _forms.scss │ │ ├── _material-design-reset.scss │ │ └── _prism.scss │ ├── stories │ │ ├── Introduction.stories.mdx │ │ ├── assets │ │ │ ├── code-brackets.svg │ │ │ ├── colors.svg │ │ │ ├── comments.svg │ │ │ ├── direction.svg │ │ │ ├── flow.svg │ │ │ ├── plugin.svg │ │ │ ├── repo.svg │ │ │ └── stackalt.svg │ │ ├── badge │ │ │ └── Badge.stories.ts │ │ ├── button │ │ │ └── Button.stories.ts │ │ ├── card │ │ │ └── Card.stories.ts │ │ ├── dropdown │ │ │ └── Dropdown.stories.ts │ │ ├── empty-state │ │ │ └── Empty-state.stories.ts │ │ ├── input │ │ │ └── Input.stories.ts │ │ ├── modal │ │ │ └── Modal.stories.ts │ │ ├── notification │ │ │ └── Notification.stories.ts │ │ ├── radio │ │ │ └── Radio.stories.ts │ │ ├── table-cell │ │ │ └── Table-cell.stories.ts │ │ ├── table-row │ │ │ └── Table-row.stories.ts │ │ ├── table │ │ │ └── Table.stories.ts │ │ ├── tag │ │ │ └── Tag.stories.ts │ │ ├── toggle │ │ │ └── Toggle.stories.ts │ │ └── tooltip │ │ │ └── Tooltip.stories.ts │ ├── styles.scss │ └── test.ts │ ├── tailwind.config.js │ ├── tsconfig.app.json │ ├── tsconfig.json │ └── tsconfig.spec.json └── worker ├── consumer.go ├── scheduler.go └── task ├── delete_archived_task.go ├── expire_secret.go ├── expire_secret_test.go ├── monitor_twitter_sources.go ├── process_batch_retry.go ├── process_batch_retry_test.go ├── process_broadcast_event_creation.go ├── process_broadcast_event_creation_test.go ├── process_dead_letters.go ├── process_dynamic_event_creation.go ├── process_dynamic_event_creation_test.go ├── process_emails.go ├── process_emails_test.go ├── process_event_channel.go ├── process_event_creation.go ├── process_event_creation_test.go ├── process_event_delivery.go ├── process_event_delivery_test.go ├── process_meta_event.go ├── process_meta_event_test.go ├── process_notifications.go ├── process_notifications_test.go ├── process_retry_event_delivery.go ├── process_retry_event_delivery_test.go ├── push_daily_telemetry.go ├── queue_stuck_event_deliveries.go ├── retention_policies.go ├── retention_policies_test.go ├── retry_event_deliveries.go ├── search_tokenizer.go ├── task.go └── testdata └── Config ├── basic-convoy-disable-endpoint.json └── basic-convoy.json /.dockerignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | node_modules 3 | docker-compose.yml 4 | 5 | # Convoy Specific 6 | typesense_data 7 | postgres_data 8 | redis_data 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 4 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.githooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # git hook that runs before a commit 4 | # this script will regenerate the swagger docs(openapi v3 soon) file 5 | 6 | pwd 7 | 8 | changed=$(git status -s | grep api) 9 | 10 | echo "$changed" 11 | 12 | # if changed is empty then exit, else regenerate the docs 13 | if [ -z "$changed" ] 14 | then 15 | exit 0 16 | else 17 | # regenerate docs 18 | swag init --generatedTime --parseDependency --parseInternal -g handlers/main.go -d api/ api/* 19 | swag fmt -d ./api 20 | go run v3gen/main.go 21 | git add docs/ # add all files under the generated doc folder to git 22 | fi 23 | 24 | exit 0 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/release-template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Release template 3 | about: This template is used to describe all the todo required for releasing a new 4 | binary 5 | title: "[Release]" 6 | labels: '' 7 | assignees: '' 8 | 9 | --- 10 | 11 | ## Release Title 12 | Example: v23.10.0 13 | 14 | ## To-do 15 | [ ] Helm Charts 16 | [ ] Documentation Release Notes 17 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Sync API Docs 🦉 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | rdme-openapi: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Check out repo 📚 13 | uses: actions/checkout@v3 14 | 15 | - name: Run `openapi` command 🚀 16 | uses: readmeio/rdme@v8 17 | with: 18 | rdme: openapi docs/v3/openapi3.json --key=${{ secrets.README_API_KEY }} --id=620fb30f3b9bf300264daa75 19 | -------------------------------------------------------------------------------- /.github/workflows/linter.yml: -------------------------------------------------------------------------------- 1 | name: golangci-lint 2 | on: 3 | pull_request: 4 | 5 | jobs: 6 | golangci: 7 | if: ${{ !(contains(github.head_ref, 'ui/')) || !(contains(github.head_ref, 'cms/')) }} 8 | name: lint 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - name: golangci-lint 13 | uses: golangci/golangci-lint-action@v6 14 | with: 15 | version: latest 16 | only-new-issues: true 17 | args: --timeout 3m --verbose 18 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { "scss.lint.unknownAtRules": "ignore" } 2 | -------------------------------------------------------------------------------- /ENT-CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 23.05.1 2 | 3 | - [Feature] Add support for Role Based Access Control #1551 #1552 4 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | v25.5.1-hotfix.1 2 | -------------------------------------------------------------------------------- /api/handlers/license.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/frain-dev/convoy/pkg/log" 7 | 8 | "github.com/frain-dev/convoy/util" 9 | "github.com/go-chi/render" 10 | ) 11 | 12 | func (h *Handler) GetLicenseFeatures(w http.ResponseWriter, r *http.Request) { 13 | v, err := h.A.Licenser.FeatureListJSON(r.Context()) 14 | if err != nil { 15 | log.FromContext(r.Context()).WithError(err).Error("failed to get license features") 16 | _ = render.Render(w, r, util.NewErrorResponse("failed to get license features", http.StatusBadRequest)) 17 | return 18 | } 19 | 20 | _ = render.Render(w, r, util.NewServerResponse("Retrieved license features successfully", v, http.StatusOK)) 21 | } 22 | -------------------------------------------------------------------------------- /api/policies/policy.go: -------------------------------------------------------------------------------- 1 | package policies 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/frain-dev/convoy/api/types" 7 | ) 8 | 9 | const AuthUserCtx types.ContextKey = "authUser" 10 | 11 | // ErrNotAllowed is returned when request is not permitted. 12 | var ErrNotAllowed = errors.New("unauthorized to process request") 13 | -------------------------------------------------------------------------------- /api/policies/policy_test.go: -------------------------------------------------------------------------------- 1 | package policies 2 | 3 | import ( 4 | "github.com/frain-dev/convoy/auth" 5 | "github.com/stretchr/testify/require" 6 | ) 7 | 8 | type basetest struct { 9 | name string 10 | authCtx *auth.AuthenticatedUser 11 | assertion require.ErrorAssertionFunc 12 | expectedError error 13 | } 14 | -------------------------------------------------------------------------------- /api/testdata/Auth_Config/no-auth-convoy.json: -------------------------------------------------------------------------------- 1 | { 2 | "base_url": "test-url", 3 | "queue": { 4 | "type": "redis", 5 | "redis": { 6 | "dsn": "abc" 7 | } 8 | }, 9 | "server": { 10 | "http": { 11 | "port": 80 12 | } 13 | }, 14 | "group": { 15 | "strategy": { 16 | "type": "default", 17 | "default": { 18 | "intervalSeconds": 125, 19 | "retryLimit": 15 20 | } 21 | }, 22 | "signature": { 23 | "header": "X-Company-Event-WebHook-Signature", 24 | "hash": "SHA256" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_BatchRetryEventDelivery/should_batch_retry_all_successfully.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"1 successful, 0 failed","data":null} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_BatchRetryEventDelivery/should_batch_retry_one_successfully.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"1 successful, 1 failed","data":null} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_BatchRetryEventDelivery/should_fail_to_find_app_endpoint.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"0 successful, 2 failed","data":null} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_BatchRetryEventDelivery/should_fail_to_load_event_deliveries.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"failed to fetch event deliveries"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_BatchRetryEventDelivery/should_fail_to_update_app_endpoints_status.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"0 successful, 1 failed","data":null} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_BatchRetryEventDelivery/should_fail_to_update_status_of_event_delivery.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"0 successful, 1 failed","data":null} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_BatchRetryEventDelivery/should_fail_to_write_to_queue.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"0 successful, 1 failed","data":null} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CountAffectedEventDeliveries/should_count_affected_event_deliveries_successfully.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"event deliveries count successful","data":{"num":10}} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CountAffectedEventDeliveries/should_fail_to_count_affected_event_deliveries.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"an error occurred while fetching event deliveries"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateAPIKey/create_api_key.golden: -------------------------------------------------------------------------------- 1 | {"uid":"","name":"","role":{"type":"ui_admin","groups":["sendcash-pay"]},"key_type":""} -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateAPIKey/create_api_key_without_expires_at_field.golden: -------------------------------------------------------------------------------- 1 | {"uid":"","name":"","role":{"type":"ui_admin","groups":["sendcash-pay"]},"key_type":""} -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateAPIKey/invalid_expiry_date.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"expiry date is invalid"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateAPIKey/invalid_role.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"invalid api key role"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateApp/invalid_request.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"body must not be empty"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateApp/invalid_request_-_no_app_name.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"name:please provide your appName"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateApp/should_fail_for_application_name_not_unique.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"an application with this name exists: ABC_DEF_TEST"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateApp/should_fail_to_check_if_application_name_is_unique.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"failed to check if application name is unique"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateApp/valid_application.golden: -------------------------------------------------------------------------------- 1 | {"uid":"","group_id":"1234567890","name":"ABC_DEF_TEST","support_email":"","slack_webhook_url":"https://google.com","is_disabled":false,"endpoints":[],"events":0} -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateAppEndpoint/should_error_for_invalid_rate_limit_duration.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"an error occurred parsing the rate limit duration: time: missing unit in duration \"1\""} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateAppEndpoint/valid_endpoint.golden: -------------------------------------------------------------------------------- 1 | {"uid":"","target_url":"https://google.com","description":"Test","status":"active","secret":"abc","http_timeout":"","rate_limit":300,"rate_limit_duration":"1h0m0s","events":["*"]} -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateAppPortalAPIKey/app_id_does_not_belong_to_group.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"app does not belong to group"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateAppPortalAPIKey/create_api_key.golden: -------------------------------------------------------------------------------- 1 | {"uid":"","name":"","role":{"type":"ui_admin","groups":["1234567890"],"apps":["123456"]},"key_type":"app_portal"} -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateGroup/invalid_request_-_no_group_hash_field.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"hash:please provide a valid hash"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateGroup/invalid_request_-_no_group_header_field.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"header:please provide a valid signature header"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateGroup/invalid_request_-_no_group_interval_seconds_field.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"intervalSeconds:please provide a valid interval seconds"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateGroup/invalid_request_-_no_group_name.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"name:please provide a valid name"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateGroup/invalid_request_-_no_group_retry_limit_field.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"retryLimit:please provide a valid interval seconds"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateGroup/invalid_request_-_no_group_strategy_type_field.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"type:please provide a valid strategy type"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateGroup/invalid_request_-_unsupported_group_hash_field.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"hash:unsupported hash type"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateGroup/invalid_request_-_unsupported_group_strategy_type.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"type:unsupported strategy type"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateGroup/should_fail_to_create_group.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"failed to create group"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_CreateGroup/valid_group.golden: -------------------------------------------------------------------------------- 1 | {"uid":"","name":"ABC_DEF_TEST_UPDATE","logo_url":"","config":{"strategy":{"type":"default","default":{"intervalSeconds":10,"retryLimit":3},"exponentialBackoff":{"retryLimit":0}},"signature":{"header":"X-Company-Signature","hash":"SHA1"},"disable_endpoint":false,"replay_attacks":false},"statistics":null,"rate_limit":5000,"rate_limit_duration":"1m"} -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_DeleteGroup/failed_group_apps_delete.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"failed to delete group apps"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_DeleteGroup/failed_group_delete.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"failed to delete group"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_DeleteGroup/failed_group_events_delete.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"failed to delete group events"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_DeleteGroup/valid_group_delete.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"Group deleted successfully","data":null} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_ForceResendEventDelivery/should_error_for_discarded_event_status.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"2 successful, 1 failed","data":null} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_ForceResendEventDelivery/should_error_for_endpoint_not_found.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"0 successful, 3 failed","data":null} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_ForceResendEventDelivery/should_error_for_failed_to_fetch_deliveries.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"failed to fetch event deliveries"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_ForceResendEventDelivery/should_error_for_failed_to_update_event_delivery_status.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"0 successful, 2 failed","data":null} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_ForceResendEventDelivery/should_error_for_inactive_endpoint.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"0 successful, 2 failed","data":null} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_ForceResendEventDelivery/should_error_for_malformed_body.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"Request is invalid"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_ForceResendEventDelivery/should_force_resend_all_successfully.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"3 successful, 0 failed","data":null} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_GetAPIKeyByID/should_fail_to_find_api_key.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"failed to fetch api key"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_GetAPIKeyByID/should_find_api_key.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"api key fetched successfully","data":{"uid":"12345","name":"","role":{"type":"","groups":null},"key_type":""}} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_GetAPIKeys/should_fail_to_load_api_keys.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"failed to load api keys"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_GetAPIKeys/should_load_api_keys.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"api keys fetched successfully","data":{"content":[{"uid":"12345","name":"","role":{"type":"","groups":null},"key_type":""}],"pagination":{"total":0,"page":0,"perPage":100,"prev":0,"next":0,"totalPage":0}}} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_GetApp/app_not_found.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"application not found"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_GetApp/valid_application.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"App fetched successfully","data":{"uid":"123456789","group_id":"1234567890","name":"Valid application","support_email":"","is_disabled":false,"endpoints":[],"events":0}} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_GetAppEndpoint/should_get_application_endpoint.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"App endpoints fetched successfully","data":[{"uid":"abc","target_url":"http://amazon.com","description":"desc","status":"","secret":"","http_timeout":"","rate_limit":0,"rate_limit_duration":"","events":null},{"uid":"def","target_url":"http://google.com","description":"desc","status":"","secret":"","http_timeout":"","rate_limit":0,"rate_limit_duration":"","events":null}]} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_GetAppEndpoints/should_get_application_endpoints.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"App endpoints fetched successfully","data":[{"uid":"abc","target_url":"http://amazon.com","description":"desc","status":"","secret":"","http_timeout":"","rate_limit":0,"rate_limit_duration":"","events":null},{"uid":"abc","target_url":"http://google.com","description":"desc","status":"","secret":"","http_timeout":"","rate_limit":0,"rate_limit_duration":"","events":null}]} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_GetApps/should_fail_to_fetch_applications.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"an error occurred while fetching apps. Error: failed to load"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_GetApps/valid_applications.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"Apps fetched successfully","data":{"content":[{"uid":"123456789","group_id":"1234567890","name":"Valid application - 0","support_email":"","is_disabled":false,"endpoints":[],"events":0}],"pagination":{"total":0,"page":0,"perPage":0,"prev":0,"next":0,"totalPage":0}}} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_GetGroup/group_not_found.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"failed to fetch group by id"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_GetGroup/should_fail_to_count_group_apps.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"failed to count group statistics"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_GetGroup/should_fail_to_count_group_messages.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"failed to count group statistics"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_GetGroup/valid_group.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"Group fetched successfully","data":{"uid":"1234567890","name":"sendcash-pay","logo_url":"","config":null,"statistics":{"messages_sent":1,"total_apps":1},"rate_limit":0,"rate_limit_duration":""}} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_GetGroups/should_error_for_invalid_group_access.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"invalid group access"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_GetGroups/should_fail_to_fetch_groups.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"an error occurred while fetching Groups"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_GetGroups/should_fetch_user_groups.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"Groups fetched successfully","data":[{"uid":"1234567890","name":"sendcash-pay","logo_url":"","config":null,"statistics":{"messages_sent":1,"total_apps":1},"rate_limit":0,"rate_limit_duration":""}]} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_GetGroups/valid_groups.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"Groups fetched successfully","data":[{"uid":"1234567890","name":"sendcash-pay","logo_url":"","config":null,"statistics":{"messages_sent":1,"total_apps":1},"rate_limit":0,"rate_limit_duration":""}]} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_RevokeAPIKey/revoke_api_key.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"api key revoked successfully","data":null} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_RevokeAPIKey/should_error_for_revoke_api_key.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"failed to revoke api key"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateAPIKey/invalid_role.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"invalid api key role"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateAPIKey/update_api_key.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"api key updated successfully","data":{"uid":"12345","name":"","role":{"type":"admin","groups":["sendcash-pay"]},"key_type":""}} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateApp/invalid_request.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"body must not be empty"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateApp/invalid_request_-_no_app_name.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"name:please provide your appName"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateApp/should_error_for_duplicate_app_name.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"an application with this name exists: ABC_DEF_TEST_UPDATE"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateApp/valid_application_update.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"App updated successfully","data":{"uid":"12345","group_id":"1234567890","name":"ABC_DEF_TEST_UPDATE","support_email":"","is_disabled":false,"endpoints":[],"events":0}} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateApp/valid_request_-_disable_application.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"App updated successfully","data":{"uid":"12345","group_id":"1234567890","name":"ABC","support_email":"","is_disabled":true,"endpoints":[],"events":0}} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateApp/valid_request_-_enable_disabled_application.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"App updated successfully","data":{"uid":"12345","group_id":"1234567890","name":"ABC","support_email":"","is_disabled":false,"endpoints":[],"events":0}} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateApp/valid_request_-_update_secret.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"App updated successfully","data":{"uid":"12345","group_id":"1234567890","name":"ABC","support_email":"","is_disabled":false,"endpoints":[],"events":0}} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateApp/valid_request_-_update_support_email.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"App updated successfully","data":{"uid":"12345","group_id":"1234567890","name":"ABC","support_email":"engineering@frain.dev","is_disabled":false,"endpoints":[],"events":0}} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateAppEndpoint/invalid_request.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"body must not be empty"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateAppEndpoint/should_error_for_endpoint_not_found.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"endpoint not found"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateAppEndpoint/should_error_for_invalid_rate_limit_duration.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"time: missing unit in duration \"1\""} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateAppEndpoint/valid_application.golden: -------------------------------------------------------------------------------- 1 | {"uid":"","target_url":"https://google.com","description":"Correct endpoint","status":"active","secret":"","http_timeout":"10s","rate_limit":3000,"rate_limit_duration":"1h0m0s","events":["payment.created"]} -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateAppEndpoint_InvalidRequest/invalid_request.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"endpoint not found"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateAppEndpoint_InvalidRequest/valid_application.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"cannot use localhost or 127.0.0.1"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateGroup/invalid_request.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"body must not be empty"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateGroup/invalid_request_-_no_group_name.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"name:please provide a valid name"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateGroup/should_fail_to_update_group.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"an error occurred while updating Group"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestApplicationHandler_UpdateGroup/valid_group_update.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"Group updated successfully","data":{"uid":"1234567890","name":"ABC_DEF_TEST_UPDATE","logo_url":"","config":{"strategy":{"type":"default","default":{"intervalSeconds":10,"retryLimit":3},"exponentialBackoff":{"retryLimit":0}},"signature":{"header":"X-Company-Signature","hash":"SHA1"},"disable_endpoint":false,"replay_attacks":false},"statistics":null,"rate_limit":0,"rate_limit_duration":""}} 2 | -------------------------------------------------------------------------------- /api/testdata/TestDashboardIntegrationTestSuiteTest/TestGetDashboardSummary/should_error_for_empty_startDate.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"please specify a startDate query"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestDashboardIntegrationTestSuiteTest/TestGetDashboardSummary/should_error_for_invalid_startDate.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"please specify a startDate in the format 2006-01-02T15:04:05"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestDashboardIntegrationTestSuiteTest/TestGetDashboardSummary/should_error_for_invalid_type.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"please specify a type query in (daily, weekly, monthly, yearly)"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestDashboardIntegrationTestSuiteTest/TestGetDashboardSummary/should_error_for_startDate_greater_than_endDate.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"invalid period 'daily': startDate cannot be greater than endDate"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestRequirePermission_Basic/authorization_failed.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"authorization failed"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestRequirePermission_Basic/credentials_not_provided.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"invalid header structure"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestRequirePermission_Basic/invalid_basic_credentials.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"invalid basic credentials"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestRequirePermission_Basic/invalid_credentials.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"invalid credentials"} 2 | -------------------------------------------------------------------------------- /api/testdata/TestRequirePermission_Basic/valid_credentials.golden: -------------------------------------------------------------------------------- 1 | Hello -------------------------------------------------------------------------------- /api/testdata/TestRequirePermission_Noop/authorization_failed.golden: -------------------------------------------------------------------------------- 1 | Hello -------------------------------------------------------------------------------- /api/testdata/TestRequirePermission_Noop/credentials_not_provided.golden: -------------------------------------------------------------------------------- 1 | Hello -------------------------------------------------------------------------------- /api/testdata/TestRequirePermission_Noop/invalid_credentials.golden: -------------------------------------------------------------------------------- 1 | Hello -------------------------------------------------------------------------------- /api/testdata/TestRequirePermission_Noop/valid_credentials.golden: -------------------------------------------------------------------------------- 1 | Hello -------------------------------------------------------------------------------- /api/testdata/Test_applicationHandler_DeleteApp/should_delete_app.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"App deleted successfully","data":null} 2 | -------------------------------------------------------------------------------- /api/testdata/Test_applicationHandler_DeleteApp/should_fail_to_delete_app.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"an error occurred while deleting app"} 2 | -------------------------------------------------------------------------------- /api/testdata/Test_applicationHandler_DeleteAppEndpoint/should_delete_app_endpoint.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"App endpoint deleted successfully","data":null} 2 | -------------------------------------------------------------------------------- /api/testdata/Test_applicationHandler_DeleteAppEndpoint/should_error_for_endpoint_not_found.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"endpoint not found"} 2 | -------------------------------------------------------------------------------- /api/testdata/Test_applicationHandler_DeleteAppEndpoint/should_fail_to_delete_app_endpoint.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"an error occurred while deleting app endpoint"} 2 | -------------------------------------------------------------------------------- /api/testdata/Test_applicationHandler_GetPaginatedApps/valid_groups.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"Apps fetched successfully","data":{"content":[{"uid":"validID","group_id":"1234567890","name":"Valid application - 0","support_email":"","is_disabled":false,"endpoints":[],"events":0}],"pagination":{"total":0,"page":0,"perPage":0,"prev":0,"next":0,"totalPage":0}}} 2 | -------------------------------------------------------------------------------- /api/testdata/Test_fetchAuthConfig/successful_auth_fetch.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"Auth details fetched successfully","data":{"type":"basic","basic":{"username":"test","password":"test"}}} 2 | -------------------------------------------------------------------------------- /api/testdata/Test_resendEventDelivery/invalid__resend_-_pending_endpoint.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"endpoint is being re-activated"} 2 | -------------------------------------------------------------------------------- /api/testdata/Test_resendEventDelivery/invalid_resend_-_event_not_failed.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"cannot resend event that did not fail previously"} 2 | -------------------------------------------------------------------------------- /api/testdata/Test_resendEventDelivery/invalid_resend_-_event_successful.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"event already sent"} 2 | -------------------------------------------------------------------------------- /api/testdata/Test_resendEventDelivery/valid_resend_-_previously_failed_-_active_endpoint.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"App event processed for retry successfully","data":{"uid":"2134453454","event_metadata":{"uid":"1122333444456","name":""},"endpoint":{"uid":"","target_url":"http://localhost","status":"active","secret":"","http_timeout":"","rate_limit":0,"rate_limit_duration":"","sent":false},"app_metadata":{"uid":"12345","title":"","group_id":"","support_email":""},"metadata":null,"status":"Scheduled"}} 2 | -------------------------------------------------------------------------------- /api/testdata/Test_resendEventDelivery/valid_resend_-_previously_failed_and_inactive_endpoint.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"App event processed for retry successfully","data":{"uid":"2134453454","event_metadata":{"uid":"1122333444456","name":""},"endpoint":{"uid":"","target_url":"http://localhost","status":"inactive","secret":"","http_timeout":"","rate_limit":0,"rate_limit_duration":"","sent":false},"app_metadata":{"uid":"12345","title":"","group_id":"","support_email":""},"metadata":null,"status":"Scheduled"}} 2 | -------------------------------------------------------------------------------- /api/testdata/Test_resendMessage/invalid__resend_-_pending_endpoint.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"endpoint is being re-activated"} 2 | -------------------------------------------------------------------------------- /api/testdata/Test_resendMessage/invalid_resend_-_event_not_failed.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"cannot resend event that did not fail previously"} 2 | -------------------------------------------------------------------------------- /api/testdata/Test_resendMessage/invalid_resend_-_event_successful.golden: -------------------------------------------------------------------------------- 1 | {"status":false,"message":"event already sent"} 2 | -------------------------------------------------------------------------------- /api/testdata/Test_resendMessage/valid_resend_-_previously_failed_-_active_endpoint.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"App event processed for retry successfully","data":{"uid":"1122333444456","app_id":"12345","event_type":"","provider_id":"","data":null,"metadata":null,"status":"Scheduled","app_metadata":{"group_id":"","secret":"","support_email":"","endpoints":[{"uid":"","target_url":"http://localhost","status":"active","sent":false}]}}} 2 | -------------------------------------------------------------------------------- /api/testdata/Test_resendMessage/valid_resend_-_previously_failed_and_inactive_endpoint.golden: -------------------------------------------------------------------------------- 1 | {"status":true,"message":"App event processed for retry successfully","data":{"uid":"1122333444456","app_id":"12345","event_type":"","provider_id":"","data":null,"metadata":null,"status":"Scheduled","app_metadata":{"group_id":"","secret":"","support_email":"","endpoints":[{"uid":"","target_url":"http://localhost","status":"inactive","sent":false}]}}} 2 | -------------------------------------------------------------------------------- /api/ui/build/go_test_stub.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/api/ui/build/go_test_stub.txt -------------------------------------------------------------------------------- /auth/realm.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import "context" 4 | 5 | type Realm interface { 6 | GetName() string 7 | Authenticate(ctx context.Context, cred *Credential) (*AuthenticatedUser, error) 8 | } 9 | -------------------------------------------------------------------------------- /cache/cache.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | rcache "github.com/frain-dev/convoy/cache/redis" 8 | "github.com/frain-dev/convoy/config" 9 | ) 10 | 11 | type Cache interface { 12 | Set(ctx context.Context, key string, data interface{}, expiration time.Duration) error 13 | Get(ctx context.Context, key string, data interface{}) error 14 | Delete(ctx context.Context, key string) error 15 | } 16 | 17 | func NewCache(cfg config.RedisConfiguration) (Cache, error) { 18 | ca, err := rcache.NewRedisCache(cfg.BuildDsn()) 19 | if err != nil { 20 | return nil, err 21 | } 22 | 23 | return ca, nil 24 | } 25 | -------------------------------------------------------------------------------- /cache/noop/noop.go: -------------------------------------------------------------------------------- 1 | package ncache 2 | 3 | import ( 4 | "context" 5 | "time" 6 | ) 7 | 8 | type NoopCache struct{} 9 | 10 | func NewNoopCache() *NoopCache { 11 | return &NoopCache{} 12 | } 13 | 14 | func (n *NoopCache) Set(ctx context.Context, key string, data interface{}, ttl time.Duration) error { 15 | return nil 16 | } 17 | 18 | func (n *NoopCache) Get(ctx context.Context, key string, data interface{}) error { 19 | return nil 20 | } 21 | 22 | func (n *NoopCache) Delete(ctx context.Context, key string) error { 23 | return nil 24 | } 25 | -------------------------------------------------------------------------------- /cmd/utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/frain-dev/convoy/internal/pkg/cli" 5 | "github.com/spf13/cobra" 6 | ) 7 | 8 | var utilsCmd = &cobra.Command{ 9 | Use: "utils", 10 | Short: "runs utility commands", 11 | Annotations: map[string]string{ 12 | "CheckMigration": "true", 13 | "ShouldBootstrap": "false", 14 | }, 15 | } 16 | 17 | func AddUtilsCommand(app *cli.App) *cobra.Command { 18 | utilsCmd.AddCommand(AddPartitionCommand(app)) 19 | utilsCmd.AddCommand(AddUnPartitionCommand(app)) 20 | 21 | utilsCmd.AddCommand(AddInitEncryptionCommand(app)) 22 | utilsCmd.AddCommand(AddRotateKeyCommand(app)) 23 | utilsCmd.AddCommand(AddRevertEncryptionCommand(app)) 24 | return utilsCmd 25 | } 26 | -------------------------------------------------------------------------------- /cmd/version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | ) 6 | 7 | func AddVersionCommand() *cobra.Command { 8 | cmd := &cobra.Command{ 9 | Use: "version", 10 | Short: "Print the version", 11 | Annotations: map[string]string{ 12 | "CheckMigration": "true", 13 | "ShouldBootstrap": "false", 14 | }, 15 | RunE: func(cmd *cobra.Command, args []string) error { 16 | root := cmd.Root() 17 | root.SetArgs([]string{"--version"}) 18 | err := root.Execute() 19 | if err != nil { 20 | return err 21 | } 22 | 23 | return nil 24 | }, 25 | PersistentPostRun: func(cmd *cobra.Command, args []string) {}, 26 | } 27 | 28 | return cmd 29 | } 30 | -------------------------------------------------------------------------------- /config/testdata/Config/empty-api-key-auth-group-name.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "scheme": "postgres", 4 | "host": "inside-config-file", 5 | "username": "postgres", 6 | "password": "postgres", 7 | "database": "convoy", 8 | "options": "sslmode=disable&connect_timeout=30", 9 | "port": 5432 10 | }, 11 | "redis": { 12 | "port": 8379, 13 | "scheme": "redis", 14 | "host": "localhost" 15 | }, 16 | "server": { 17 | "http": { 18 | "port": 80 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /config/testdata/Config/empty-api-key.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "scheme": "postgres", 4 | "host": "inside-config-file", 5 | "username": "postgres", 6 | "password": "postgres", 7 | "database": "convoy", 8 | "options": "sslmode=disable&connect_timeout=30", 9 | "port": 5432 10 | }, 11 | "redis": { 12 | "port": 8379, 13 | "scheme": "redis", 14 | "host": "localhost" 15 | }, 16 | "server": { 17 | "http": { 18 | "port": 80 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /config/testdata/Config/empty-redis-dsn.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "scheme": "postgres", 4 | "host": "inside-config-file", 5 | "username": "postgres", 6 | "password": "postgres", 7 | "database": "convoy", 8 | "options": "sslmode=disable&connect_timeout=30", 9 | "port": 5432 10 | }, 11 | "redis": { 12 | "scheme": "", 13 | "host": "", 14 | "username": "", 15 | "password": "", 16 | "database": "", 17 | "port": 0 18 | }, 19 | "server": { 20 | "http": { 21 | "port": 80 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /config/testdata/Config/empty-ssl-cert-file.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "scheme": "postgres", 4 | "host": "inside-config-file", 5 | "username": "postgres", 6 | "password": "postgres", 7 | "database": "convoy", 8 | "options": "sslmode=disable&connect_timeout=30", 9 | "port": 5432 10 | }, 11 | "redis": { 12 | "port": 8379, 13 | "scheme": "redis", 14 | "host": "localhost" 15 | }, 16 | "server": { 17 | "http": { 18 | "ssl": true, 19 | "ssl_key_file": "abc", 20 | "ssl_cert_file": "", 21 | "port": 80 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /config/testdata/Config/empty-ssl-key-file.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "scheme": "postgres", 4 | "host": "inside-config-file", 5 | "username": "postgres", 6 | "password": "postgres", 7 | "database": "convoy", 8 | "options": "sslmode=disable&connect_timeout=30", 9 | "port": 5432 10 | }, 11 | "redis": { 12 | "port": 8379, 13 | "scheme": "redis", 14 | "host": "localhost" 15 | }, 16 | "server": { 17 | "http": { 18 | "ssl": true, 19 | "ssl_key_file": "", 20 | "ssl_cert_file": "abc", 21 | "port": 80 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /config/testdata/Config/no-port-convoy.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "scheme": "postgres", 4 | "host": "inside-config-file", 5 | "username": "postgres", 6 | "password": "postgres", 7 | "database": "convoy", 8 | "options": "sslmode=disable&connect_timeout=30", 9 | "port": 5432 10 | }, 11 | "redis": { 12 | "port": 8379, 13 | "scheme": "redis", 14 | "host": "localhost" 15 | }, 16 | "server": { 17 | "http": {} 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /config/testdata/Config/too-large-max-response-size-convoy.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "scheme": "postgres", 4 | "host": "inside-config-file", 5 | "username": "postgres", 6 | "password": "postgres", 7 | "database": "convoy", 8 | "options": "sslmode=disable&connect_timeout=30", 9 | "port": 5432 10 | }, 11 | "redis": { 12 | "port": 8379, 13 | "scheme": "redis", 14 | "host": "localhost" 15 | }, 16 | "max_response_size": 55, 17 | "server": { 18 | "http": { 19 | "port": 80 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /config/testdata/Config/unknown-strategy-type.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "scheme": "postgres", 4 | "host": "inside-config-file", 5 | "username": "postgres", 6 | "password": "postgres", 7 | "database": "convoy", 8 | "options": "sslmode=disable&connect_timeout=30", 9 | "port": 5432 10 | }, 11 | "redis": { 12 | "port": 8379, 13 | "scheme": "redis", 14 | "host": "localhost" 15 | }, 16 | "server": { 17 | "http": { 18 | "port": 80 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /config/testdata/Config/valid-convoy-redis-cluster.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "scheme": "postgres", 4 | "host": "inside-config-file", 5 | "username": "postgres", 6 | "password": "postgres", 7 | "database": "convoy", 8 | "options": "sslmode=disable&connect_timeout=30", 9 | "port": 5432 10 | }, 11 | "redis": { 12 | "addresses": "localhost:7001,localhost:7002,localhost:7003,localhost:7004,localhost:7005,localhost:7006" 13 | }, 14 | "max_response_size": 40, 15 | "server": { 16 | "http": { 17 | "port": 80 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /config/testdata/Config/valid-convoy.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "scheme": "postgres", 4 | "host": "inside-config-file", 5 | "username": "postgres", 6 | "password": "postgres", 7 | "database": "convoy", 8 | "options": "sslmode=disable&connect_timeout=30", 9 | "port": 5432 10 | }, 11 | "redis": { 12 | "port": 8379, 13 | "scheme": "redis", 14 | "host": "localhost" 15 | }, 16 | "retention_policy": { 17 | "enabled": true, 18 | "policy": "720h" 19 | }, 20 | "max_response_size": 40, 21 | "server": { 22 | "http": { 23 | "port": 80 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /config/testdata/Config/zero-max-response-size-convoy.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "scheme": "postgres", 4 | "host": "inside-config-file", 5 | "username": "postgres", 6 | "password": "postgres", 7 | "database": "convoy", 8 | "options": "sslmode=disable&connect_timeout=30", 9 | "port": 5432 10 | }, 11 | "redis": { 12 | "port": 8379, 13 | "scheme": "redis", 14 | "host": "localhost" 15 | }, 16 | "server": { 17 | "http": { 18 | "port": 80 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /config/testdata/Test_ConfigurationFromEnvironment/convoy.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "scheme": "postgres", 4 | "host": "inside-config-file", 5 | "username": "postgres", 6 | "password": "postgres", 7 | "database": "convoy", 8 | "options": "sslmode=disable&connect_timeout=30", 9 | "port": 5432 10 | }, 11 | "redis": { 12 | "port": 8379, 13 | "scheme": "redis", 14 | "host": "localhost" 15 | }, 16 | "server": { 17 | "http": { 18 | "port": 8080 19 | } 20 | }, 21 | "auth": { 22 | "require_auth": true, 23 | "native": { 24 | "enabled": true 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /configs/caddyfile: -------------------------------------------------------------------------------- 1 | localhost 2 | -------------------------------------------------------------------------------- /configs/local/conf/userlists.txt: -------------------------------------------------------------------------------- 1 | "convoy" "pg_password" 2 | -------------------------------------------------------------------------------- /configs/local/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ./cmd migrate up 4 | ./cmd server --config convoy.json 5 | -------------------------------------------------------------------------------- /const.go: -------------------------------------------------------------------------------- 1 | package convoy 2 | 3 | import "time" 4 | 5 | const ( 6 | HttpPost HttpMethod = "POST" 7 | HttpGet HttpMethod = "GET" 8 | ) 9 | 10 | const ( 11 | HTTP_RATE_LIMIT = 25 12 | HTTP_RATE_LIMIT_PER_MIN = HTTP_RATE_LIMIT * 60 13 | 14 | INGRESS_RATE_LIMIT = 100 15 | INGRESS_RATE_LIMIT_PER_MIN = HTTP_RATE_LIMIT * 60 16 | 17 | EGRESS_RATE_LIMIT = 100 18 | EGRESS_RATE_LIMIT_PER_MIN = HTTP_RATE_LIMIT * 60 19 | 20 | HTTP_TIMEOUT = 10 21 | HTTP_TIMEOUT_IN_DURATION = time.Duration(HTTP_TIMEOUT) * time.Second 22 | ) 23 | -------------------------------------------------------------------------------- /convoy.go: -------------------------------------------------------------------------------- 1 | package convoy 2 | -------------------------------------------------------------------------------- /database/database.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "context" 5 | "github.com/frain-dev/convoy/database/hooks" 6 | "github.com/jmoiron/sqlx" 7 | ) 8 | 9 | type Database interface { 10 | GetDB() *sqlx.DB 11 | GetReadDB() *sqlx.DB 12 | BeginTx(context.Context) (*sqlx.Tx, error) 13 | GetHook() *hooks.Hook 14 | Rollback(tx *sqlx.Tx, err error) 15 | Close() error 16 | } 17 | -------------------------------------------------------------------------------- /database/sqlite3/sqlite3.go: -------------------------------------------------------------------------------- 1 | package sqlite3 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/jmoiron/sqlx" 7 | _ "github.com/mattn/go-sqlite3" 8 | ) 9 | 10 | const pkgName = "sqlite3" 11 | 12 | type Sqlite struct { 13 | dbx *sqlx.DB 14 | } 15 | 16 | func NewDB() (*Sqlite, error) { 17 | db, err := sqlx.Connect("sqlite3", "convoy.db") 18 | if err != nil { 19 | return nil, fmt.Errorf("[%s]: failed to open database - %v", pkgName, err) 20 | } 21 | return &Sqlite{dbx: db}, nil 22 | } 23 | 24 | func (s *Sqlite) GetDB() *sqlx.DB { 25 | return s.dbx 26 | } 27 | -------------------------------------------------------------------------------- /datastore/testdata/organisations.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - id: 2dade341-799e-4bb7-bf4a-b04a23b551c3 3 | org_name: Convoy Inc 4 | 5 | -------------------------------------------------------------------------------- /ee/VERSION: -------------------------------------------------------------------------------- 1 | v25.2.2 Enterprise Edition 2 | -------------------------------------------------------------------------------- /internal/pkg/limiter/limiter.go: -------------------------------------------------------------------------------- 1 | package limiter 2 | 3 | import ( 4 | "context" 5 | "github.com/frain-dev/convoy/config" 6 | rlimiter "github.com/frain-dev/convoy/internal/pkg/limiter/redis" 7 | ) 8 | 9 | type RateLimiter interface { 10 | // Allow rate limits outgoing events to endpoints based on a rate in a specified time duration by the endpoint id 11 | Allow(ctx context.Context, key string, rate int) error 12 | AllowWithDuration(ctx context.Context, key string, rate int, duration int) error 13 | } 14 | 15 | func NewLimiter(cfg config.Configuration) (RateLimiter, error) { 16 | r, err := rlimiter.NewRedisLimiter(cfg.Redis.BuildDsn()) 17 | if err != nil { 18 | return nil, err 19 | } 20 | 21 | return r, nil 22 | } 23 | -------------------------------------------------------------------------------- /internal/pkg/memorystore/row.go: -------------------------------------------------------------------------------- 1 | package memorystore 2 | 3 | type Row struct { 4 | key string 5 | value interface{} 6 | } 7 | 8 | func NewRow(key string, value interface{}) *Row { 9 | return &Row{ 10 | key: key, 11 | value: value, 12 | } 13 | } 14 | 15 | func (r *Row) Key() string { 16 | return r.key 17 | } 18 | 19 | func (r *Row) Value() interface{} { 20 | return r.value 21 | } 22 | -------------------------------------------------------------------------------- /internal/pkg/object-store/onprem.go: -------------------------------------------------------------------------------- 1 | package objectstore 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/frain-dev/convoy/pkg/log" 7 | ) 8 | 9 | type OnPremClient struct { 10 | opts ObjectStoreOptions 11 | } 12 | 13 | func NewOnPremClient(opts ObjectStoreOptions) (ObjectStore, error) { 14 | client := &OnPremClient{ 15 | opts: opts, 16 | } 17 | return client, nil 18 | 19 | } 20 | 21 | func (o *OnPremClient) Save(filename string) error { 22 | if _, err := os.Stat(filename); err != nil { 23 | return err 24 | } 25 | log.Printf("Successfully saved %q \n", filename) 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /internal/pkg/smtp/smtp_test.go: -------------------------------------------------------------------------------- 1 | package smtp 2 | -------------------------------------------------------------------------------- /internal/pkg/socket/socket.go: -------------------------------------------------------------------------------- 1 | package socket 2 | 3 | type WebSocketConnection interface { 4 | Close() error 5 | SetReadLimit(limit int64) 6 | SetPingHandler(h func(appData string) error) 7 | WriteMessage(messageType int, data []byte) error 8 | ReadMessage() (messageType int, p []byte, err error) 9 | } 10 | -------------------------------------------------------------------------------- /internal/pkg/tracer/noop.go: -------------------------------------------------------------------------------- 1 | package tracer 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/frain-dev/convoy/config" 8 | ) 9 | 10 | // NoOpBackend is a no-operation tracer backend implementation. 11 | type NoOpBackend struct{} 12 | 13 | func (NoOpBackend) Init(string) error { return nil } 14 | func (NoOpBackend) Type() config.TracerProvider { 15 | return "" 16 | } 17 | func (NoOpBackend) Capture(context.Context, string, map[string]interface{}, time.Time, time.Time) {} 18 | func (NoOpBackend) Shutdown(context.Context) error { 19 | return nil 20 | } 21 | -------------------------------------------------------------------------------- /pkg/flatten/types.go: -------------------------------------------------------------------------------- 1 | package flatten 2 | 3 | type M = map[string]interface{} 4 | -------------------------------------------------------------------------------- /pkg/models/webhook.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | // WebhookSchema represents a webhook schema extracted from OpenAPI spec 4 | type WebhookSchema struct { 5 | Name string `json:"name"` 6 | Description string `json:"description,omitempty"` 7 | Schema map[string]interface{} `json:"schema"` 8 | } 9 | 10 | // WebhookCollection represents a collection of webhook schemas 11 | type WebhookCollection struct { 12 | ProjectID string `json:"project_id"` 13 | Webhooks []WebhookSchema `json:"webhooks"` 14 | } 15 | -------------------------------------------------------------------------------- /pkg/msgpack/msgpack.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "bytes" 5 | "github.com/vmihailenco/msgpack/v5" 6 | ) 7 | 8 | func EncodeMsgPack(payload interface{}) ([]byte, error) { 9 | var buf bytes.Buffer 10 | enc := msgpack.NewEncoder(&buf) 11 | enc.SetCustomStructTag("json") 12 | 13 | err := enc.Encode(payload) 14 | if err != nil { 15 | return nil, err 16 | } 17 | 18 | return buf.Bytes(), nil 19 | } 20 | 21 | func DecodeMsgPack(pack []byte, target interface{}) error { 22 | var buf bytes.Buffer 23 | buf.Write(pack) 24 | 25 | enc := msgpack.NewDecoder(&buf) 26 | enc.SetCustomStructTag("json") 27 | 28 | err := enc.Decode(&target) 29 | if err != nil { 30 | return err 31 | } 32 | 33 | return nil 34 | } 35 | -------------------------------------------------------------------------------- /pkg/url/url_query.go: -------------------------------------------------------------------------------- 1 | package url 2 | 3 | import "net/url" 4 | 5 | func ConcatQueryParams(targetURL, query string) (string, error) { 6 | u, err := url.Parse(targetURL) 7 | if err != nil { 8 | return "", err 9 | } 10 | 11 | parsedValues, err := url.ParseQuery(query) 12 | if err != nil { 13 | return "", err 14 | } 15 | 16 | q := u.Query() 17 | 18 | for k, v := range parsedValues { 19 | for _, s := range v { 20 | q.Add(k, s) 21 | } 22 | } 23 | 24 | u.RawQuery = q.Encode() 25 | 26 | return u.String(), nil 27 | } 28 | -------------------------------------------------------------------------------- /plugin.go: -------------------------------------------------------------------------------- 1 | package convoy 2 | 3 | import "net/http" 4 | 5 | type Plugin interface { 6 | Apply(http.ResponseWriter, *http.Request) error 7 | Name() string 8 | IsEnabled() bool 9 | } 10 | -------------------------------------------------------------------------------- /plugins/add_headers_plugin.go: -------------------------------------------------------------------------------- 1 | package convoy 2 | 3 | import "net/http" 4 | 5 | type AddHeadersPlugin struct { 6 | config map[string]string 7 | } 8 | 9 | func (a *AddHeadersPlugin) Apply(w http.ResponseWriter, r *http.Request) error { 10 | 11 | for k, v := range a.config { 12 | w.Header().Add(k, v) 13 | } 14 | 15 | return nil 16 | } 17 | 18 | func (a *AddHeadersPlugin) Name() string { return "Add Headers" } 19 | 20 | func (a *AddHeadersPlugin) IsEnabled() bool { return len(a.config) > 0 } 21 | -------------------------------------------------------------------------------- /prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | evaluation_interval: 15s 4 | 5 | scrape_configs: 6 | - job_name: prometheus 7 | static_configs: 8 | - targets: ['prometheus:9090'] 9 | - job_name: agent 10 | metrics_path: /metrics 11 | static_configs: 12 | - targets: ["agent:5008"] 13 | - job_name: web 14 | metrics_path: /metrics 15 | static_configs: 16 | - targets: ["web:5005"] 17 | - job_name: worker 18 | metrics_path: /metrics 19 | static_configs: 20 | - targets: ["worker:5006"] 21 | - job_name: ingest 22 | metrics_path: /metrics 23 | static_configs: 24 | - targets: ["ingest:5009"] 25 | -------------------------------------------------------------------------------- /queue/queue.go: -------------------------------------------------------------------------------- 1 | package queue 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/frain-dev/convoy" 7 | "github.com/frain-dev/convoy/internal/pkg/rdb" 8 | ) 9 | 10 | type Queuer interface { 11 | Write(convoy.TaskName, convoy.QueueName, *Job) error 12 | Options() QueueOptions 13 | } 14 | 15 | type Job struct { 16 | ID string `json:"id"` 17 | Payload []byte `json:"payload"` 18 | Delay time.Duration `json:"delay"` 19 | } 20 | 21 | type QueueOptions struct { 22 | Names map[string]int 23 | Type string 24 | RedisClient *rdb.Redis 25 | RedisAddress []string 26 | PrometheusAddress string 27 | } 28 | -------------------------------------------------------------------------------- /queue/testdata/convoy_redis.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "dsn": "mongodb://inside-config-file" 4 | }, 5 | "queue": { 6 | "type": "redis", 7 | "redis": { 8 | "dsn": "redis://localhost:6379" 9 | } 10 | }, 11 | "server": { 12 | "http": { 13 | "port": 80 14 | } 15 | }, 16 | "group": { 17 | "strategy": { 18 | "type": "default", 19 | "default": { 20 | "intervalSeconds": 125, 21 | "retryLimit": 15 22 | } 23 | }, 24 | "signature": { 25 | "hash": "SHA256" 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /release.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.20.2 2 | 3 | # Define a build-time argument 4 | ARG IMAGE_SHA 5 | 6 | # Set an environment variable using the ARG 7 | ENV CORE_GATEWAY_IMAGE_SHA=${IMAGE_SHA} 8 | 9 | # Copy the Convoy binary 10 | COPY convoy /cmd 11 | 12 | # Copy the migrations directory 13 | COPY sql/ /sql/ 14 | 15 | # Copy the startup script 16 | COPY configs/local/start.sh /start.sh 17 | 18 | # Set permissions 19 | RUN chmod +x /cmd /start.sh 20 | 21 | # Install necessary dependencies 22 | RUN apk add --no-cache gcompat 23 | 24 | # Set the startup command 25 | CMD ["/start.sh"] 26 | 27 | -------------------------------------------------------------------------------- /retrystrategies/default.go: -------------------------------------------------------------------------------- 1 | package retrystrategies 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type DefaultRetryStrategy struct { 8 | intervalSeconds uint64 9 | } 10 | 11 | func (r *DefaultRetryStrategy) NextDuration(attempts uint64) time.Duration { 12 | return time.Duration(r.intervalSeconds) * time.Second 13 | } 14 | 15 | func NewDefault(intervalSeconds uint64) *DefaultRetryStrategy { 16 | return &DefaultRetryStrategy{ 17 | intervalSeconds: intervalSeconds, 18 | } 19 | } 20 | 21 | var _ RetryStrategy = (*DefaultRetryStrategy)(nil) 22 | -------------------------------------------------------------------------------- /retrystrategies/retry.go: -------------------------------------------------------------------------------- 1 | package retrystrategies 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/frain-dev/convoy/datastore" 7 | ) 8 | 9 | type RetryStrategy interface { 10 | // NextDuration is how long we should wait before next retry 11 | NextDuration(attempts uint64) time.Duration 12 | } 13 | 14 | func NewRetryStrategyFromMetadata(m datastore.Metadata) RetryStrategy { 15 | if string(m.Strategy) == string(datastore.ExponentialStrategyProvider) { 16 | return NewExponential(m.IntervalSeconds, m.MaxRetrySeconds) 17 | } 18 | 19 | return NewDefault(m.IntervalSeconds) 20 | } 21 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # export CGO_ENABLED=0 4 | # export GOOS=linux 5 | # export GOARCH=arm64 6 | 7 | buildConvoy() { 8 | echo "Building Convoy ..." 9 | 10 | # Build UI. 11 | UIDIR="api/ui/build" 12 | 13 | # Remove build folder 14 | rm -rf $UIDIR 15 | 16 | # Recreate build folder 17 | mkdir $UIDIR 18 | 19 | # Enter UI directory 20 | cd ./web/ui/dashboard 21 | 22 | # Install dependencies 23 | npm i 24 | 25 | # Run production build 26 | npm run build 27 | 28 | # Copy build artifacts 29 | cd ../../../ 30 | mv web/ui/dashboard/dist/* $UIDIR 31 | 32 | # Build Binary 33 | go build -o convoy ./cmd/*.go 34 | } 35 | 36 | buildConvoy 37 | -------------------------------------------------------------------------------- /scripts/integration-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export TEST_DB_SCHEME=postgres 4 | export TEST_DB_OPTIONS="sslmode=disable&connect_timeout=30" 5 | export TEST_DB_HOST=localhost 6 | export TEST_DB_USERNAME=postgres 7 | export TEST_DB_PASSWORD=postgres 8 | export TEST_DB_DATABASE=test 9 | export TEST_DB_PORT=5432 10 | 11 | export TEST_REDIS_SCHEME=redis 12 | export TEST_REDIS_HOST=localhost 13 | export TEST_REDIS_PORT=6379 14 | 15 | make integration_tests 16 | 17 | make docker_e2e_tests 18 | -------------------------------------------------------------------------------- /scripts/release.sh: -------------------------------------------------------------------------------- 1 | # Set version 2 | tag=$1 3 | etag="$tag Enterprise Edition" 4 | : > ./VERSION && echo $tag > VERSION 5 | : > ./ee/VERSION && echo $etag > ./ee/VERSION 6 | 7 | # Commit version number & push 8 | git add VERSION ./ee/VERSION 9 | git commit -m "Bump version to $tag" 10 | git push origin 11 | 12 | # Tag & Push. 13 | git tag $tag 14 | git push origin $tag 15 | -------------------------------------------------------------------------------- /scripts/replica-set.sh: -------------------------------------------------------------------------------- 1 | docker exec mongo1 mongosh --eval "rs.initiate({ 2 | _id: \"myReplicaSet\", 3 | members: [ 4 | {_id: 0, host: \"mongo1\"}, 5 | {_id: 1, host: \"mongo2\"}, 6 | {_id: 2, host: \"mongo3\"} 7 | ] 8 | })" 9 | -------------------------------------------------------------------------------- /services/errors.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | type ServiceError struct { 4 | ErrMsg string 5 | Err error 6 | } 7 | 8 | func (a *ServiceError) Error() string { 9 | return a.ErrMsg 10 | } 11 | 12 | func (a *ServiceError) Unwrap() error { 13 | return a.Err 14 | } 15 | -------------------------------------------------------------------------------- /slim.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gcr.io/distroless/base 2 | # the name of the binary generated by goreleaser 3 | COPY convoy /cmd 4 | ENTRYPOINT [ "/cmd" ] 5 | CMD ["server", "--config", "convoy.json"] -------------------------------------------------------------------------------- /sql/1679836136.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | CREATE TABLE IF NOT EXISTS convoy.devices_backup AS SELECT * FROM convoy.devices; 3 | ALTER TABLE convoy.devices DROP COLUMN endpoint_id; 4 | DROP TABLE IF EXISTS convoy.devices_backup; 5 | 6 | -- +migrate Down 7 | CREATE TABLE IF NOT EXISTS convoy.devices_backup AS SELECT * FROM convoy.devices; 8 | ALTER TABLE convoy.devices ADD COLUMN endpoint_id CHAR(26) REFERENCES convoy.endpoints (id); 9 | DROP TABLE IF EXISTS convoy.devices_backup; 10 | 11 | -------------------------------------------------------------------------------- /sql/1684884904.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE convoy.meta_events ALTER COLUMN id TYPE VARCHAR; 3 | ALTER TABLE convoy.project_configurations ALTER COLUMN id TYPE VARCHAR; 4 | ALTER TABLE convoy.source_verifiers ALTER COLUMN id TYPE VARCHAR; 5 | 6 | -- +migrate Down 7 | ALTER TABLE convoy.meta_events ALTER COLUMN id TYPE CHAR(26); 8 | ALTER TABLE convoy.project_configurations ALTER COLUMN id TYPE CHAR(26); 9 | ALTER TABLE convoy.source_verifiers ALTER COLUMN id TYPE CHAR(26); 10 | -------------------------------------------------------------------------------- /sql/1684918027.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | CREATE UNIQUE INDEX IF NOT EXISTS organisation_invites_invitee_email_1 ON convoy.organisation_invites(organisation_id, invitee_email, deleted_at) NULLS NOT DISTINCT; 3 | 4 | DROP INDEX IF EXISTS convoy.organisation_invites_invitee_email; 5 | 6 | ALTER INDEX convoy.organisation_invites_invitee_email_1 RENAME TO organisation_invites_invitee_email; 7 | 8 | -- +migrate Down 9 | CREATE UNIQUE INDEX IF NOT EXISTS organisation_invites_invitee_email_1 ON convoy.organisation_invites(organisation_id, invitee_email); 10 | 11 | DROP INDEX IF EXISTS convoy.organisation_invites_invitee_email; 12 | 13 | ALTER INDEX convoy.organisation_invites_invitee_email_1 RENAME TO organisation_invites_invitee_email; 14 | 15 | -------------------------------------------------------------------------------- /sql/1684929840.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE convoy.sources ADD COLUMN IF NOT EXISTS custom_response_body VARCHAR; 3 | ALTER TABLE convoy.sources ADD COLUMN IF NOT EXISTS custom_response_content_type VARCHAR; 4 | -- +migrate Down 5 | ALTER TABLE convoy.sources DROP COLUMN IF EXISTS custom_response_content_type; 6 | ALTER TABLE convoy.sources DROP COLUMN IF EXISTS custom_response_body; 7 | 8 | -------------------------------------------------------------------------------- /sql/1685202737.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE convoy.portal_links 3 | ADD COLUMN IF NOT EXISTS owner_id VARCHAR, 4 | ADD COLUMN IF NOT EXISTS can_manage_endpoint BOOLEAN, 5 | ALTER COLUMN can_manage_endpoint SET DEFAULT false, 6 | ALTER COLUMN endpoints DROP NOT NULL; 7 | 8 | -- +migrate Up 9 | CREATE INDEX IF NOT EXISTS idx_portal_links_owner_id_key ON convoy.portal_links (owner_id); 10 | 11 | -- +migrate Down 12 | ALTER TABLE convoy.portal_links 13 | DROP COLUMN IF EXISTS owner_id, 14 | DROP COLUMN IF EXISTS can_manage_endpoint; 15 | 16 | -- +migrate Down 17 | DROP INDEX IF EXISTS convoy.idx_portal_links_owner_id_key; 18 | -------------------------------------------------------------------------------- /sql/1686048402.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE convoy.events ADD COLUMN IF NOT EXISTS url_query_params VARCHAR; 3 | ALTER TABLE convoy.event_deliveries ADD COLUMN IF NOT EXISTS url_query_params VARCHAR; 4 | 5 | -- +migrate Down 6 | ALTER TABLE convoy.events DROP COLUMN IF EXISTS url_query_params; 7 | ALTER TABLE convoy.event_deliveries DROP COLUMN IF EXISTS url_query_params; 8 | -------------------------------------------------------------------------------- /sql/1692024707.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE convoy.endpoints 3 | ADD CONSTRAINT endpoints_title_project_id_pk 4 | UNIQUE (title, project_id, deleted_at); 5 | 6 | -- +migrate Down 7 | ALTER TABLE convoy.endpoints 8 | DROP CONSTRAINT IF EXISTS endpoints_title_project_id_pk; 9 | -------------------------------------------------------------------------------- /sql/1693908172.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE convoy.subscriptions ADD COLUMN IF NOT EXISTS function TEXT; 3 | 4 | -- +migrate Down 5 | ALTER TABLE IF EXISTS convoy.subscriptions DROP COLUMN IF EXISTS function; 6 | 7 | -------------------------------------------------------------------------------- /sql/1698074481.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE convoy.configurations ADD COLUMN s3_prefix text; 3 | 4 | -- +migrate Down 5 | ALTER TABLE convoy.configurations DROP COLUMN s3_prefix; 6 | 7 | -------------------------------------------------------------------------------- /sql/1698683940.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE convoy.event_deliveries ADD COLUMN IF NOT EXISTS latency TEXT; 3 | 4 | -- +migrate Down 5 | ALTER TABLE convoy.event_deliveries DROP COLUMN IF EXISTS latency; 6 | 7 | -------------------------------------------------------------------------------- /sql/1704372039.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE convoy.event_deliveries ADD COLUMN IF NOT EXISTS event_type TEXT; 3 | CREATE INDEX IF NOT EXISTS event_deliveries_event_type_1 ON convoy.event_deliveries(event_type); 4 | 5 | -- +migrate Down 6 | ALTER TABLE convoy.event_deliveries DROP COLUMN IF EXISTS event_type; 7 | DROP INDEX IF EXISTS convoy.event_deliveries_event_type_1; 8 | -------------------------------------------------------------------------------- /sql/1709568783.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | CREATE INDEX IF NOT EXISTS idx_project_id_on_not_deleted ON convoy.events(project_id) WHERE deleted_at IS NULL; 3 | 4 | -- +migrate Down 5 | DROP INDEX IF EXISTS idx_project_id_on_not_deleted; 6 | 7 | 8 | -------------------------------------------------------------------------------- /sql/1710685343.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE IF EXISTS convoy.sources DROP COLUMN IF EXISTS function; 3 | ALTER TABLE convoy.sources ADD COLUMN IF NOT EXISTS body_function TEXT; 4 | ALTER TABLE convoy.sources ADD COLUMN IF NOT EXISTS header_function TEXT; 5 | ALTER TABLE convoy.project_configurations ADD COLUMN IF NOT EXISTS multiple_endpoint_subscriptions bool NOT NULL DEFAULT FALSE; 6 | 7 | -- +migrate Down 8 | ALTER TABLE IF EXISTS convoy.sources DROP COLUMN IF EXISTS body_function; 9 | ALTER TABLE IF EXISTS convoy.sources DROP COLUMN IF EXISTS header_function; 10 | ALTER TABLE IF EXISTS convoy.project_configurations DROP COLUMN IF EXISTS multiple_endpoint_subscriptions; 11 | -------------------------------------------------------------------------------- /sql/1710763531.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE convoy.project_configurations ADD COLUMN IF NOT EXISTS ssl_enforce_secure_endpoints BOOLEAN DEFAULT TRUE; 3 | 4 | -- +migrate Down 5 | ALTER TABLE convoy.project_configurations DROP COLUMN IF EXISTS ssl_enforce_secure_endpoints; 6 | -------------------------------------------------------------------------------- /sql/1718819653.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE convoy.subscriptions ADD COLUMN filter_config_filter_is_flattened BOOLEAN DEFAULT false; 3 | 4 | -- +migrate Down 5 | ALTER TABLE convoy.subscriptions DROP COLUMN filter_config_filter_is_flattened; 6 | -------------------------------------------------------------------------------- /sql/1719521272.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE convoy.events ADD COLUMN IF NOT EXISTS acknowledged_at TIMESTAMPTZ DEFAULT NULL; 3 | ALTER TABLE convoy.event_deliveries ADD COLUMN IF NOT EXISTS acknowledged_at TIMESTAMPTZ DEFAULT NULL; 4 | 5 | -- +migrate Down 6 | ALTER TABLE convoy.events DROP COLUMN IF EXISTS acknowledged_at; 7 | ALTER TABLE convoy.event_deliveries DROP COLUMN IF EXISTS acknowledged_at; 8 | -------------------------------------------------------------------------------- /sql/1719521273.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE convoy.event_deliveries ADD COLUMN IF NOT EXISTS latency_seconds numeric DEFAULT NULL; 3 | 4 | -- +migrate Down 5 | ALTER TABLE convoy.event_deliveries DROP COLUMN IF EXISTS latency_seconds; 6 | -------------------------------------------------------------------------------- /sql/1729585620.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | CREATE INDEX IF NOT EXISTS idx_delivery_attempts_event_delivery_id_created_at_desc ON convoy.delivery_attempts(event_delivery_id, created_at DESC); 3 | 4 | -- +migrate Down 5 | DROP INDEX IF EXISTS convoy.idx_delivery_attempts_event_delivery_id_created_at_desc; 6 | -------------------------------------------------------------------------------- /sql/1729709223.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE convoy.users ADD COLUMN IF NOT EXISTS auth_type TEXT NOT NULL DEFAULT 'local'; 3 | 4 | -- +migrate Down 5 | ALTER TABLE convoy.users DROP COLUMN IF EXISTS auth_type; 6 | -------------------------------------------------------------------------------- /sql/1733488138.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | create unique index if not exists idx_event_types_name_project_id 3 | on convoy.event_types (project_id, name); 4 | 5 | -- +migrate Down 6 | drop index if exists convoy.idx_event_types_name_project_id; 7 | -------------------------------------------------------------------------------- /sql/1733518672.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | ALTER TABLE convoy.endpoints 3 | ADD COLUMN IF NOT EXISTS is_encrypted BOOLEAN DEFAULT FALSE, 4 | ADD COLUMN IF NOT EXISTS secrets_cipher bytea, 5 | ADD COLUMN IF NOT EXISTS authentication_type_api_key_header_value_cipher bytea; 6 | 7 | CREATE INDEX idx_endpoints_is_encrypted ON convoy.endpoints (is_encrypted); 8 | 9 | -- +migrate Down 10 | DROP INDEX IF EXISTS idx_endpoints_is_encrypted; 11 | 12 | ALTER TABLE convoy.endpoints 13 | DROP COLUMN IF EXISTS is_encrypted, 14 | DROP COLUMN IF EXISTS secrets_cipher, 15 | DROP COLUMN IF EXISTS authentication_type_api_key_header_value_cipher; 16 | -------------------------------------------------------------------------------- /sql/1735652782.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | alter table convoy.subscriptions add column filter_config_filter_raw_headers jsonb not null default '{}'; 3 | alter table convoy.subscriptions add column filter_config_filter_raw_body jsonb not null default '{}'; 4 | 5 | update convoy.subscriptions 6 | set 7 | filter_config_filter_raw_headers = filter_config_filter_headers, 8 | filter_config_filter_raw_body = filter_config_filter_body 9 | where 10 | id > ''; 11 | 12 | -- +migrate Down 13 | alter table convoy.subscriptions drop column filter_config_filter_raw_headers; 14 | alter table convoy.subscriptions drop column filter_config_filter_raw_body; 15 | 16 | -------------------------------------------------------------------------------- /sql/1736807673.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | update convoy.delivery_attempts set response_data = '' where id > ''; 3 | alter table convoy.delivery_attempts 4 | alter column response_data type bytea 5 | using response_data::bytea; 6 | 7 | -- +migrate Down 8 | alter table convoy.delivery_attempts 9 | alter column response_data type text 10 | using encode(response_data, 'escape'); 11 | -------------------------------------------------------------------------------- /sql/1742902597.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | alter table convoy.event_types add column json_schema jsonb default '{}'; 3 | 4 | -- +migrate Down 5 | alter table convoy.event_types drop column json_schema; 6 | -------------------------------------------------------------------------------- /sql/1745514784.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | create table if not exists convoy.portal_tokens ( 3 | id varchar primary key, 4 | portal_link_id varchar not null, 5 | token_mask_id text default '', 6 | token_hash text default '', 7 | token_salt text default '', 8 | token_expires_at timestamptz default null, 9 | created_at timestamptz default current_timestamp, 10 | updated_at timestamptz default current_timestamp, 11 | deleted_at timestamptz, 12 | constraint fk_portal_links 13 | foreign key (portal_link_id) 14 | references convoy.portal_links(id) 15 | on delete cascade 16 | ); 17 | 18 | -- +migrate Down 19 | drop table if exists convoy.portal_tokens; -------------------------------------------------------------------------------- /test/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | 5 | mongodb: 6 | image: mongo:latest 7 | environment: 8 | MONGO_INITDB_ROOT_USERNAME: root 9 | MONGO_INITDB_ROOT_PASSWORD: rootpassword 10 | ports: 11 | - "57017:27017" 12 | volumes: 13 | - ./data/mongo:/data/db 14 | -------------------------------------------------------------------------------- /testcon/manifest/counter.go: -------------------------------------------------------------------------------- 1 | package manifest 2 | 3 | import ( 4 | "sync" 5 | "sync/atomic" 6 | ) 7 | 8 | var ctrLock = sync.RWMutex{} 9 | 10 | func DecrementAndGet(ctr *atomic.Int64) int64 { 11 | ctrLock.Lock() 12 | defer ctrLock.Unlock() 13 | ctr.Add(-1) 14 | return ctr.Load() 15 | } 16 | -------------------------------------------------------------------------------- /testcon/manifest/endpoint.go: -------------------------------------------------------------------------------- 1 | package manifest 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | var endpoints = map[string]int{} 9 | var lock = sync.RWMutex{} 10 | 11 | func ReadEndpoint(k string) int { 12 | lock.RLock() 13 | defer lock.RUnlock() 14 | return endpoints[k] 15 | } 16 | 17 | func WriteEndpoint(k string, v int) { 18 | lock.Lock() 19 | defer lock.Unlock() 20 | endpoints[k] = v 21 | } 22 | 23 | func IncEndpoint(k string) { 24 | lock.Lock() 25 | defer lock.Unlock() 26 | count := endpoints[k] 27 | count++ 28 | endpoints[k] = count 29 | } 30 | 31 | func PrintEndpoints() { 32 | lock.RLock() 33 | defer lock.RUnlock() 34 | fmt.Printf("Size: %d Endpoints: %+v\n", len(endpoints), endpoints) 35 | } 36 | -------------------------------------------------------------------------------- /testcon/manifest/event.go: -------------------------------------------------------------------------------- 1 | package manifest 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | var events = map[string]int{} 9 | var evLock = sync.RWMutex{} 10 | 11 | func ReadEvent(k string) int { 12 | evLock.RLock() 13 | defer evLock.RUnlock() 14 | return events[k] 15 | } 16 | 17 | func WriteEvent(k string, v int) { 18 | evLock.Lock() 19 | defer evLock.Unlock() 20 | events[k] = v 21 | } 22 | 23 | func IncEvent(k string) { 24 | evLock.Lock() 25 | defer evLock.Unlock() 26 | count := events[k] 27 | count++ 28 | events[k] = count 29 | } 30 | 31 | func PrintEvents() { 32 | evLock.RLock() 33 | defer evLock.RUnlock() 34 | fmt.Printf("Size: %d Events: %+v\n", len(events), events) 35 | } 36 | -------------------------------------------------------------------------------- /util/db.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | func BoolToText(b bool) string { 4 | if b { 5 | return "true" 6 | } else { 7 | return "false" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /util/header.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "net/http" 5 | "strings" 6 | 7 | "github.com/frain-dev/convoy/datastore" 8 | ) 9 | 10 | // ConvertDefaultHeaderToCustomHeader converts http.Header to convoy.HttpHeader 11 | func ConvertDefaultHeaderToCustomHeader(h *http.Header) *datastore.HttpHeader { 12 | res := make(datastore.HttpHeader) 13 | for k, v := range *h { 14 | res[k] = strings.Join(v, " ") 15 | } 16 | 17 | return &res 18 | } 19 | -------------------------------------------------------------------------------- /util/slice.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | // Difference returns the items present in a, that 4 | // are not found in b. E.g. 5 | // E.g. Difference([1,2,3], [1,2]) = [3] 6 | func Difference(a, b []string) []string { 7 | mb := make(map[string]struct{}, len(b)) 8 | for _, x := range b { 9 | mb[x] = struct{}{} 10 | } 11 | 12 | var diff []string 13 | for _, x := range a { 14 | if _, found := mb[x]; !found { 15 | diff = append(diff, x) 16 | } 17 | } 18 | 19 | return diff 20 | } 21 | -------------------------------------------------------------------------------- /web/ui/dashboard/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 4 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "tabWidth": 4, 4 | "printWidth": 280, 5 | "semi": true, 6 | "endOfLine": "auto", 7 | "arrowParens": "avoid", 8 | "bracketSpacing": true, 9 | "htmlWhitespaceSensitivity": "ignore", 10 | "insertPragma": false, 11 | "jsxBracketSameLine": true, 12 | "jsxSingleQuote": false, 13 | "proseWrap": "preserve", 14 | "quoteProps": "as-needed", 15 | "requirePragma": false, 16 | "trailingComma": "none", 17 | "useTabs": true, 18 | "vueIndentScriptAndStyle": false 19 | } 20 | -------------------------------------------------------------------------------- /web/ui/dashboard/.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "stories": [ 3 | "../src/**/*.stories.mdx", 4 | "../src/**/*.stories.@(js|jsx|ts|tsx)" 5 | ], 6 | "addons": [ 7 | "@storybook/addon-links", 8 | "@storybook/addon-essentials", 9 | "@storybook/addon-interactions" 10 | ], 11 | "framework": "@storybook/angular", 12 | "core": { 13 | "builder": "@storybook/builder-webpack5" 14 | } 15 | } -------------------------------------------------------------------------------- /web/ui/dashboard/.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import { setCompodocJson } from "@storybook/addon-docs/angular"; 2 | import docJson from "../documentation.json"; 3 | setCompodocJson(docJson); 4 | 5 | export const parameters = { 6 | actions: { argTypesRegex: "^on[A-Z].*" }, 7 | controls: { 8 | matchers: { 9 | color: /(background|color)$/i, 10 | date: /Date$/, 11 | }, 12 | }, 13 | docs: { inlineStories: true }, 14 | } -------------------------------------------------------------------------------- /web/ui/dashboard/.storybook/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.app.json", 3 | "compilerOptions": { 4 | "types": [ 5 | "node" 6 | ], 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "exclude": [ 10 | "../src/test.ts", 11 | "../src/**/*.spec.ts", 12 | "../projects/**/*.spec.ts" 13 | ], 14 | "include": [ 15 | "../src/**/*", 16 | "../projects/**/*" 17 | ], 18 | "files": [ 19 | "./typings.d.ts" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /web/ui/dashboard/.storybook/typings.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.md' { 2 | const content: string; 3 | export default content; 4 | } 5 | -------------------------------------------------------------------------------- /web/ui/dashboard/documentation.json: -------------------------------------------------------------------------------- 1 | { 2 | "pipes": [], 3 | "interfaces": [], 4 | "injectables": [], 5 | "guards": [], 6 | "interceptors": [], 7 | "classes": [], 8 | "directives": [], 9 | "components": [], 10 | "modules": [], 11 | "miscellaneous": [], 12 | "routes": [], 13 | "coverage": { 14 | "count": 0, 15 | "status": "low", 16 | "files": [] 17 | } 18 | } -------------------------------------------------------------------------------- /web/ui/dashboard/purgecss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | safelist: ['tag--Failure', 'tag--Retry', 'tag--Success'] 3 | }; 4 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/app.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/app.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import posthog from 'posthog-js'; 3 | import { environment } from 'src/environments/environment'; 4 | 5 | @Component({ 6 | selector: 'app-root', 7 | templateUrl: './app.component.html', 8 | styleUrls: ['./app.component.scss'] 9 | }) 10 | export class AppComponent { 11 | constructor() { 12 | if (window.location.hostname === 'dashboard.getconvoy.io') posthog.init(environment.posthog, { api_host: 'https://app.posthog.com', ui_host: 'https://dashboard.getconvoy.io' }); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { NotificationComponent } from 'src/app/components/notification/notification.component'; 4 | 5 | import { AppRoutingModule } from './app-routing.module'; 6 | import { AppComponent } from './app.component'; 7 | import { NotificationModalComponent } from './components/notification-modal/notification-modal.component'; 8 | 9 | @NgModule({ 10 | declarations: [AppComponent], 11 | imports: [BrowserModule, AppRoutingModule, NotificationComponent, NotificationModalComponent], 12 | bootstrap: [AppComponent] 13 | }) 14 | export class AppModule {} 15 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/badge/badge.component.html: -------------------------------------------------------------------------------- 1 |
2 |
{{ firstletters }}
3 |
{{ text }}
4 |
5 |
6 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/badge/badge.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/badge/badge.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/badge/badge.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { BadgeComponent } from './badge.component'; 4 | 5 | describe('BadgeComponent', () => { 6 | let component: BadgeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ BadgeComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(BadgeComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/button/button.component.html: -------------------------------------------------------------------------------- 1 | {{ buttonText }} 2 | 3 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/button/button.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/button/button.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/card/card.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CardComponent } from './card.component'; 4 | 5 | describe('CardComponent', () => { 6 | let component: CardComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [ CardComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(CardComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/chart/chart.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/chart/chart.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/chart/chart.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ChartComponent } from './chart.component'; 4 | 5 | describe('ChartComponent', () => { 6 | let component: ChartComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ ChartComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(ChartComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/components.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | @NgModule({ 5 | declarations: [], 6 | imports: [CommonModule], 7 | exports: [] 8 | }) 9 | export class ComponentsModule {} 10 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/copy-button/copy-button.component.html: -------------------------------------------------------------------------------- 1 |
2 | 8 |
9 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/copy-button/copy-button.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/copy-button/copy-button.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/date-picker/date-picker.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/date-picker/date-picker.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/dialog/dialog.directive.spec.ts: -------------------------------------------------------------------------------- 1 | import { DialogDirective } from './dialog.directive'; 2 | 3 | describe('DialogDirective', () => { 4 | it('should create an instance', () => { 5 | const directive = new DialogDirective(); 6 | expect(directive).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/dropdown-container/dropdown-container.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/dropdown-container/dropdown-container.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/dropdown-container/dropdown-container.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/dropdown/dropdown.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 | 7 |
8 | 9 |
10 |
11 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/dropdown/dropdown.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/dropdown/dropdown.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/empty-state/empty-state.component.html: -------------------------------------------------------------------------------- 1 |
2 | empty state 3 |

{{ heading }}

4 |

{{ description }}

5 | 6 |
7 | 8 |
9 |
10 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/empty-state/empty-state.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/empty-state/empty-state.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/file-input/file-input.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/file-input/file-input.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/github-star/github-star.component.html: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/github-star/github-star.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/github-star/github-star.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/github-star/github-star.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | @Component({ 5 | selector: 'convoy-github-star', 6 | standalone: true, 7 | imports: [CommonModule], 8 | templateUrl: './github-star.component.html', 9 | styleUrls: ['./github-star.component.scss'] 10 | }) 11 | export class GithubStarComponent implements OnInit { 12 | 13 | constructor() { } 14 | 15 | ngOnInit(): void { 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/input/input.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/input/input.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/input/input.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { InputComponent } from './input.component'; 4 | 5 | describe('InputComponent', () => { 6 | let component: InputComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [ InputComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(InputComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/multi-input/multi-input.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/multi-input/multi-input.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/notification-modal/notification-modal.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | Success gif 4 |

{{ notification.message }}

5 | 6 |
7 |
8 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/notification-modal/notification-modal.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/notification-modal/notification-modal.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/notification/notification.component.html: -------------------------------------------------------------------------------- 1 |
6 |
7 | toast icon 8 | {{ notification.message }} 9 |
10 | 13 |
14 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/notification/notification.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/notification/notification.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/overlay/overlay.directive.spec.ts: -------------------------------------------------------------------------------- 1 | import { OverlayDirective } from './overlay.directive'; 2 | 3 | describe('OverlayDirective', () => { 4 | it('should create an instance', () => { 5 | const directive = new OverlayDirective(); 6 | expect(directive).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/overlay/overlay.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, Input } from '@angular/core'; 2 | 3 | @Directive({ 4 | selector: '[convoyOverlay]', 5 | standalone: true, 6 | host: { class: 'fixed h-screen w-screen top-0 right-0 bottom-0 z-[5]', '[class]': "overlayHasBackdrop ? 'bg-black bg-opacity-50':''" } 7 | }) 8 | export class OverlayDirective { 9 | @Input('overlayHasBackdrop') overlayHasBackdrop = false; 10 | 11 | constructor() {} 12 | } 13 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/page/page.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PageComponent } from './page.component'; 4 | 5 | describe('PageComponent', () => { 6 | let component: PageComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ PageComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(PageComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/page/page.component.ts: -------------------------------------------------------------------------------- 1 | import { Directive, Input } from '@angular/core'; 2 | 3 | @Directive({ 4 | selector: '[convoy-page]', 5 | standalone: true, 6 | host: { class: 'w-full m-auto', '[class]': 'types[size]' } 7 | }) 8 | export class PageDirective { 9 | @Input('size') size: 'sm' | 'md' | 'lg' = 'lg'; 10 | types = { sm: 'max-w-[848px] bg-white-100 rounded-8px mt-10', lg: 'max-w-[1440px] px-8 pb-8', md: 'max-w-[1161px] bg-white-100 rounded-8px mt-10' }; 11 | 12 | constructor() {} 13 | } 14 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/radio/radio.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/radio/radio.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/radio/radio.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RadioComponent } from './radio.component'; 4 | 5 | describe('RadioComponent', () => { 6 | let component: RadioComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ RadioComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(RadioComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/select/select.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/select/select.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/skeleton-loader/skeleton-loader.component.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/skeleton-loader/skeleton-loader.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/skeleton-loader/skeleton-loader.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/skeleton-loader/skeleton-loader.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | @Component({ 5 | selector: 'convoy-skeleton-loader', 6 | standalone: true, 7 | imports: [CommonModule], 8 | templateUrl: './skeleton-loader.component.html', 9 | styleUrls: ['./skeleton-loader.component.scss'] 10 | }) 11 | export class SkeletonLoaderComponent implements OnInit { 12 | @Input('className') class!: string; 13 | 14 | constructor() {} 15 | 16 | ngOnInit(): void {} 17 | } 18 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/table/table.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { TableComponent } from './table.component'; 4 | 5 | describe('TableComponent', () => { 6 | let component: TableComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [ TableComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(TableComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/tag/tag.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { TagComponent } from './tag.component'; 4 | 5 | describe('TagComponent', () => { 6 | let component: TagComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [ TagComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(TagComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/time-picker/time-picker.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/time-picker/time-picker.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/toggle/toggle.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/toggle/toggle.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/components/tooltip/tooltip.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/components/tooltip/tooltip.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/guards/iframe/iframe.guard.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { IframeGuard } from './iframe.guard'; 4 | 5 | describe('IframeGuard', () => { 6 | let guard: IframeGuard; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | guard = TestBed.inject(IframeGuard); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(guard).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/guards/iframe/iframe.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { CanActivate } from '@angular/router'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class IframeGuard implements CanActivate { 8 | canActivate(): boolean { 9 | return window.self === window.top; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/interceptor/http.interceptor.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { HttpIntercepter } from './http.interceptor'; 4 | 5 | describe('HttpIntercepter', () => { 6 | beforeEach(() => 7 | TestBed.configureTestingModule({ 8 | providers: [HttpIntercepter] 9 | }) 10 | ); 11 | 12 | it('should be created', () => { 13 | const interceptor: HttpIntercepter = TestBed.inject(HttpIntercepter); 14 | expect(interceptor).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/models/device.model.ts: -------------------------------------------------------------------------------- 1 | export interface DEVICE { 2 | created_at: string; 3 | deleted_at: string; 4 | host_name: string; 5 | last_seen_at: string; 6 | status: 'offline' | 'online'; 7 | uid: string; 8 | updated_at: string; 9 | } 10 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/models/filter.model.ts: -------------------------------------------------------------------------------- 1 | export interface FILTER { 2 | uid: string; 3 | subscription_id: string; 4 | event_type: string; 5 | headers: any; 6 | body: any; 7 | is_new?: boolean; 8 | raw_headers?: any; 9 | raw_body?: any; 10 | created_at?: string; 11 | updated_at?: string; 12 | } 13 | 14 | export interface FILTER_CREATE_REQUEST { 15 | subscription_id: string; 16 | event_type: string; 17 | headers?: any; 18 | body?: any; 19 | raw_headers?: any; 20 | raw_body?: any; 21 | } 22 | 23 | export interface FILTER_TEST_REQUEST { 24 | subscription_id: string; 25 | event_type: string; 26 | sample_payload: any; 27 | } 28 | 29 | export interface FILTER_TEST_RESPONSE { 30 | data: boolean; 31 | } 32 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/models/flipt.model.ts: -------------------------------------------------------------------------------- 1 | export interface FLIPT_API_RESPONSE { 2 | requestId: string; 3 | responses: FLIPT_RESPONSE[]; 4 | requestDurationMillis: 0; 5 | } 6 | 7 | export interface FLIPT_RESPONSE { 8 | requestId: string; 9 | entityId: string; 10 | requestContext: { [key: string]: string[] }; 11 | match: boolean; 12 | flagKey: string; 13 | segmentKey: string; 14 | timestamp: string; 15 | value: string; 16 | requestDurationMillis: 0; 17 | attachment: string; 18 | } 19 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/models/user.model.ts: -------------------------------------------------------------------------------- 1 | export interface USER { 2 | created_at: string; 3 | deleted_at: string; 4 | email: string; 5 | email_verified: boolean; 6 | first_name: string; 7 | last_name: string; 8 | reset_password_expires_at: string; 9 | uid: string; 10 | updated_at: string; 11 | } 12 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/pipes/formatSeconds/format-seconds.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { FormatSecondsPipe } from './format-seconds.pipe'; 2 | 3 | describe('FormatSecondsPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new FormatSecondsPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/pipes/formatSeconds/format-seconds.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'formatSeconds', 5 | standalone: true 6 | }) 7 | export class FormatSecondsPipe implements PipeTransform { 8 | 9 | transform(timeValue?: number): unknown { 10 | if (timeValue && timeValue >= 60) { 11 | const timeInMinutes = Math.floor(timeValue / 60); 12 | const remainderSeconds = timeValue % 60; 13 | return `${timeInMinutes}m${remainderSeconds ? `${remainderSeconds}s` : ''}`; 14 | } 15 | 16 | return `${timeValue ? timeValue : 0}s`; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/pipes/role/role.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { RolePipe } from './role.pipe'; 2 | 3 | describe('RolePipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new RolePipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/pipes/role/role.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'role', 5 | standalone: true 6 | }) 7 | export class RolePipe implements PipeTransform { 8 | transform(value: string): string { 9 | switch (value) { 10 | case 'super_user': 11 | return 'Super User'; 12 | case 'admin': 13 | return 'Admin'; 14 | case 'member': 15 | return 'Member'; 16 | default: 17 | return '-'; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/pipes/source-value/source-value.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { SourceValuePipe } from './source-value.pipe'; 4 | 5 | @NgModule({ 6 | declarations: [SourceValuePipe], 7 | imports: [CommonModule], 8 | exports: [SourceValuePipe] 9 | }) 10 | export class SourceValueModule {} 11 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/pipes/source-value/source-value.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { SourceValuePipe } from './source-value.pipe'; 2 | 3 | describe('SourceValuePipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new SourceValuePipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/pipes/status-color/status-color.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { StatusColorPipe } from './status-color.pipe'; 4 | 5 | @NgModule({ 6 | declarations: [StatusColorPipe], 7 | imports: [CommonModule], 8 | exports: [StatusColorPipe] 9 | }) 10 | export class StatusColorModule {} 11 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/pipes/status-color/status-color.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { StatusColorPipe } from '../status-color/status-color.pipe'; 2 | 3 | describe('StatusColorPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new StatusColorPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/portal/create-portal-transform-function/create-portal-transform-function.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/portal/create-portal-transform-function/create-portal-transform-function.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/portal/endpoints/endpoints.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/portal/endpoints/endpoints.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/portal/event-deliveries/event-deliveries.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/portal/event-deliveries/event-deliveries.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/portal/event-delivery/event-delivery.component.html: -------------------------------------------------------------------------------- 1 |
2 | 10 | 11 | 12 |
13 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/portal/event-delivery/event-delivery.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/portal/event-delivery/event-delivery.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/portal/portal.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/portal/portal.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/portal/portal.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PortalComponent } from './portal.component'; 4 | 5 | describe('PortalComponent', () => { 6 | let component: PortalComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [ PortalComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(PortalComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/portal/portal.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { PortalService } from './portal.service'; 4 | 5 | describe('PortalService', () => { 6 | let service: PortalService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(PortalService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/portal/subscriptions/subscriptions.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/portal/subscriptions/subscriptions.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/config-button/config-button.component.html: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/create-endpoint/create-endpoint.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/components/create-endpoint/create-endpoint.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/create-endpoint/create-endpoint.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { CreateEndpointService } from './create-endpoint.service'; 4 | 5 | describe('CreateEndpointService', () => { 6 | let service: CreateEndpointService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(CreateEndpointService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/create-portal-link/create-portal-link.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/components/create-portal-link/create-portal-link.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/create-portal-link/create-portal-link.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { CreatePortalLinkService } from './create-portal-link.service'; 4 | 5 | describe('CreatePortalLinkService', () => { 6 | let service: CreatePortalLinkService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(CreatePortalLinkService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/create-project-component/create-project-component.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/components/create-project-component/create-project-component.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/create-project-component/create-project-component.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { CreateProjectComponentService } from './create-project-component.service'; 4 | 5 | describe('CreateProjectService', () => { 6 | let service: CreateProjectComponentService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(CreateProjectComponentService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/create-source/create-source.component.scss: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/create-source/create-source.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { CreateSourceService } from './create-source.service'; 4 | 5 | describe('CreateSourceService', () => { 6 | let service: CreateSourceService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(CreateSourceService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/create-subscription-filter/create-subscription-filter.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/components/create-subscription-filter/create-subscription-filter.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/create-subscription/create-subscription.component.scss: -------------------------------------------------------------------------------- 1 | .input--multiple .tag { 2 | margin-bottom: 2px; 3 | padding: 2px 4px; 4 | margin-right: 4px; 5 | } 6 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/create-subscription/create-subscription.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { CreateSubscriptionService } from './create-subscription.service'; 4 | 5 | describe('CreateSubscriptionService', () => { 6 | let service: CreateSubscriptionService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(CreateSubscriptionService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/create-transform-function/create-transform-function.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/components/create-transform-function/create-transform-function.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/delete-modal/delete-modal.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/components/delete-modal/delete-modal.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/enterprise/enterprise.directive.spec.ts: -------------------------------------------------------------------------------- 1 | import { EnterpriseDirective } from '../enterprise/enterprise.directive'; 2 | 3 | describe('EnterpriseDirective', () => { 4 | it('should create an instance', () => { 5 | const directive = new EnterpriseDirective(); 6 | expect(directive).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/enterprise/enterprise.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, OnInit, TemplateRef, ViewContainerRef } from '@angular/core'; 2 | import { environment } from 'src/environments/environment'; 3 | 4 | @Directive({ 5 | selector: '[convoy-enterprise]', 6 | standalone: true 7 | }) 8 | export class EnterpriseDirective implements OnInit { 9 | constructor(private templateReference: TemplateRef, private viewContainerReference: ViewContainerRef) {} 10 | 11 | ngOnInit(): void { 12 | const isEnterprise = environment.enterprise; 13 | if (isEnterprise) { 14 | this.viewContainerReference.createEmbeddedView(this.templateReference); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/event-delivery-filter/event-delivery-filter.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/components/event-delivery-filter/event-delivery-filter.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/loader/loader.component.html: -------------------------------------------------------------------------------- 1 |
2 | loader 3 |
4 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/loader/loader.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/components/loader/loader.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/loader/loader.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'convoy-loader, [convoy-loader]', 5 | templateUrl: './loader.component.html', 6 | styleUrls: ['./loader.component.scss'] 7 | }) 8 | export class LoaderComponent implements OnInit { 9 | @Input() isTransparent: boolean = false; 10 | @Input() position: 'absolute' | 'fixed' | 'relative' = 'absolute'; 11 | 12 | constructor() {} 13 | 14 | ngOnInit(): void {} 15 | } 16 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/loader/loader.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { LoaderComponent } from './loader.component'; 4 | 5 | @NgModule({ 6 | declarations: [LoaderComponent], 7 | imports: [CommonModule], 8 | exports: [LoaderComponent] 9 | }) 10 | export class LoaderModule {} 11 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/monaco/monaco.component.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/monaco/monaco.component.scss: -------------------------------------------------------------------------------- 1 | .monaco-editor .margin { 2 | @apply bg-transparent; 3 | } 4 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/monaco/monaco.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { MonacoService } from './monaco.service'; 4 | 5 | describe('MonacoService', () => { 6 | let service: MonacoService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(MonacoService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/pagination/pagination.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/components/pagination/pagination.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/permission/permission.directive.spec.ts: -------------------------------------------------------------------------------- 1 | import { PermissionDirective } from './permission.directive'; 2 | 3 | describe('PermissionDirective', () => { 4 | it('should create an instance', () => { 5 | const directive = new PermissionDirective(); 6 | expect(directive).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/prism/prism.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/components/prism/prism.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/prism/prism.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { PrismComponent } from './prism.component'; 4 | import { ButtonComponent } from 'src/app/components/button/button.component'; 5 | 6 | @NgModule({ 7 | declarations: [PrismComponent], 8 | imports: [CommonModule, ButtonComponent], 9 | exports: [PrismComponent] 10 | }) 11 | export class PrismModule {} 12 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/sdk-documentation/sdk-documentation.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/components/sdk-documentation/sdk-documentation.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/table-loader/table-loader.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/components/table-loader/table-loader.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/table-loader/table-loader.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'convoy-table-loader', 5 | templateUrl: './table-loader.component.html', 6 | styleUrls: ['./table-loader.component.scss'] 7 | }) 8 | export class TableLoaderComponent implements OnInit { 9 | @Input() tableHead!: string[]; 10 | @Input() withDate = true; 11 | loaderIndex: number[] = [0, 1, 2, 3, 4]; 12 | constructor() {} 13 | 14 | ngOnInit(): void {} 15 | } 16 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/token-modal/token-modal.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/components/token-modal/token-modal.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/verify-email/verify-email.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/components/verify-email/verify-email.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/components/verify-email/verify-email.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { VerifyEmailService } from './verify-email.service'; 4 | 5 | describe('VerifyEmailService', () => { 6 | let service: VerifyEmailService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(VerifyEmailService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/account/account.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/account/account.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/account/account.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { AccountService } from './account.service'; 4 | 5 | describe('AccountService', () => { 6 | let service: AccountService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(AccountService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/account/personal-settings/personal-settings.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/account/personal-settings/personal-settings.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/account/profile-settings/profile-settings.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/account/profile-settings/profile-settings.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/account/security-settings/security-settings.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/account/security-settings/security-settings.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/app/app.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/app/app.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('DashboardComponent', () => { 6 | let component: AppComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [AppComponent] 12 | }).compileComponents(); 13 | }); 14 | 15 | beforeEach(() => { 16 | fixture = TestBed.createComponent(AppComponent); 17 | component = fixture.componentInstance; 18 | fixture.detectChanges(); 19 | }); 20 | 21 | it('should create', () => { 22 | expect(component).toBeTruthy(); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { DomSanitizer } from '@angular/platform-browser'; 3 | import { ActivatedRoute } from '@angular/router'; 4 | 5 | @Component({ 6 | selector: 'app-app', 7 | templateUrl: './app.component.html', 8 | styleUrls: ['./app.component.scss'] 9 | }) 10 | export class AppComponent implements OnInit { 11 | token: string = this.route.snapshot.params.token; 12 | iframeURL = this.sanitizer.bypassSecurityTrustResourceUrl(`/app/${this.token}`); 13 | 14 | constructor(private route: ActivatedRoute, private sanitizer: DomSanitizer) {} 15 | 16 | ngOnInit() {} 17 | } 18 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { RouterModule, Routes } from '@angular/router'; 4 | import { AppComponent } from './app.component'; 5 | 6 | const routes: Routes = [{ path: '', component: AppComponent }]; 7 | 8 | @NgModule({ 9 | declarations: [AppComponent], 10 | imports: [CommonModule, RouterModule.forChild(routes)], 11 | providers: [] 12 | }) 13 | export class AppModule {} 14 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/create-project/create-project.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/create-project/create-project.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/dashboard/dashboard.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/dashboard/dashboard.component.scss: -------------------------------------------------------------------------------- 1 | // .filter { 2 | // .select { 3 | // &::after { 4 | // background: url('/assets/img/angle-arrow-down.svg'); 5 | // } 6 | // } 7 | // } 8 | // input[type='checkbox'], 9 | // input[type='radio'] { 10 | // &::after { 11 | // content: url('/assets/img/checkbox-icon.svg'); 12 | // } 13 | // } 14 | 15 | // .name { 16 | // min-width: 70px; 17 | // } 18 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/dashboard/dashboard.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-dashboard', 5 | templateUrl: './dashboard.component.html', 6 | styleUrls: ['./dashboard.component.scss'] 7 | }) 8 | export class DashboardComponent implements OnInit { 9 | 10 | constructor() { 11 | } 12 | 13 | async ngOnInit() { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/dashboard/dashboard.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { RouterModule, Routes } from '@angular/router'; 4 | import { DashboardComponent } from './dashboard.component'; 5 | 6 | const routes: Routes = [{ path: '', component: DashboardComponent }]; 7 | 8 | @NgModule({ 9 | declarations: [DashboardComponent], 10 | imports: [CommonModule, RouterModule.forChild(routes)], 11 | providers: [] 12 | }) 13 | export class DashboardModule {} 14 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/onboarding/onboarding.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/onboarding/onboarding.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/endpoints/endpoint-secret/endpoint-secret.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/project/endpoints/endpoint-secret/endpoint-secret.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/endpoints/endpoints.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/project/endpoints/endpoints.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/endpoints/endpoints.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { EndpointsService } from './endpoints.service'; 4 | 5 | describe('EndpointsService', () => { 6 | let service: EndpointsService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(EndpointsService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/event-logs/event-logs.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/project/event-logs/event-logs.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/event-logs/event-logs.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { EventLogsService } from './event-logs.service'; 4 | 5 | describe('EventLogsService', () => { 6 | let service: EventLogsService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(EventLogsService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/events/event-deliveries/event-deliveries.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/project/events/event-deliveries/event-deliveries.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/events/event-delivery-details-page/event-delivery-details-page.component.html: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/events/event-delivery-details-page/event-delivery-details-page.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/project/events/event-delivery-details-page/event-delivery-details-page.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/events/event-delivery-details/event-delivery-details.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/project/events/event-delivery-details/event-delivery-details.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/events/event-delivery-details/event-delivery-details.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { EventDeliveryDetailsService } from './event-delivery-details.service'; 4 | 5 | describe('EventDeliveryDetailsService', () => { 6 | let service: EventDeliveryDetailsService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(EventDeliveryDetailsService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/events/events.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/project/events/events.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/events/events.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { EventsService } from './events.service'; 4 | 5 | describe('EventsService', () => { 6 | let service: EventsService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(EventsService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/meta-events/meta-events.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/project/meta-events/meta-events.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/meta-events/meta-events.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { MetaEventsService } from './meta-events.service'; 4 | 5 | describe('MetaEventsService', () => { 6 | let service: MetaEventsService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(MetaEventsService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/portal-links/portal-links.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/project/portal-links/portal-links.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/portal-links/portal-links.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { PortalLinksService } from './portal-links.service'; 4 | 5 | describe('PortalLinksService', () => { 6 | let service: PortalLinksService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(PortalLinksService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/project.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/project/project.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/project.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { PROJECT } from 'src/app/models/project.model'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class ProjectService { 8 | activeProjectDetails?: PROJECT; 9 | 10 | constructor() {} 11 | } 12 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/settings/settings.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/project/settings/settings.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/sources/sources.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { SourcesService } from './sources.service'; 4 | 5 | describe('SourcesService', () => { 6 | let service: SourcesService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(SourcesService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/project/subscriptions/subscriptions.component.scss: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/projects/projects.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/projects/projects.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/settings/configurations/configurations.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/settings/configurations/configurations.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/settings/organisation-settings/organisation-settings.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/settings/organisation-settings/organisation-settings.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/settings/settings.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/settings/settings.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/settings/settings.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { SettingsService } from './settings.service'; 4 | 5 | describe('SettingsService', () => { 6 | let service: SettingsService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(SettingsService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/settings/teams/teams.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/settings/teams/teams.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/settings/teams/teams.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { TeamsService } from './teams.service'; 4 | 5 | describe('TeamsService', () => { 6 | let service: TeamsService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(TeamsService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/pages/setup-project/setup-project.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/pages/setup-project/setup-project.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/private-routing.ee.module.ts: -------------------------------------------------------------------------------- 1 | import { inject, NgModule } from '@angular/core'; 2 | import { RouterModule } from '@angular/router'; 3 | import { PrivateService } from './private.service'; 4 | import { routes } from './private-routers'; 5 | 6 | // export const fetchOrganisations = async (privateService = inject(PrivateService)) => await privateService.getOrganizations(); 7 | 8 | routes[0].children?.push({ 9 | path: 'ee', 10 | loadComponent: () => import('./pages/onboarding/onboarding.component').then(mod => mod.OnboardingComponent) 11 | }); 12 | 13 | @NgModule({ 14 | imports: [RouterModule.forChild(routes)], 15 | exports: [RouterModule] 16 | }) 17 | export class PrivateRoutingModule {} 18 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/private-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { inject, NgModule } from '@angular/core'; 2 | import { RouterModule } from '@angular/router'; 3 | import { PrivateService } from './private.service'; 4 | import { routes } from './private-routers'; 5 | 6 | // export const fetchOrganisations = async (privateService = inject(PrivateService)) => await privateService.getOrganizations(); 7 | 8 | @NgModule({ 9 | imports: [RouterModule.forChild(routes)], 10 | exports: [RouterModule] 11 | }) 12 | export class PrivateRoutingModule {} 13 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/private/private.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/private/private.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/accept-invite/accept-invite.component.scss: -------------------------------------------------------------------------------- 1 | .logo-2 { 2 | img { 3 | height: 150px; 4 | width: 150px; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/accept-invite/accept-invite.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { AcceptInviteService } from './accept-invite.service'; 4 | 5 | describe('AcceptInviteService', () => { 6 | let service: AcceptInviteService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(AcceptInviteService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/forgot-password/forgot-password.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/public/forgot-password/forgot-password.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/forgot-password/forgot-password.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { ForgotPasswordService } from './forgot-password.service'; 4 | 5 | describe('ForgotPasswordService', () => { 6 | let service: ForgotPasswordService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(ForgotPasswordService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/login/login.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/public/login/login.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/login/login.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { LoginService } from './login.service'; 4 | 5 | describe('LoginService', () => { 6 | let service: LoginService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(LoginService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/public.component.html: -------------------------------------------------------------------------------- 1 |
2 | 7 |
8 | 9 |
10 |
11 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/public.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/public/public.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/public.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PublicComponent } from './public.component'; 4 | 5 | describe('PublicComponent', () => { 6 | let component: PublicComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ PublicComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(PublicComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/public.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'convoy-public', 5 | templateUrl: './public.component.html', 6 | styleUrls: ['./public.component.scss'] 7 | }) 8 | export class PublicComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/reset-password/reset-password.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/public/reset-password/reset-password.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/reset-password/reset-password.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { ResetPasswordService } from './reset-password.service'; 4 | 5 | describe('ResetPasswordService', () => { 6 | let service: ResetPasswordService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(ResetPasswordService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/saml/saml.component.html: -------------------------------------------------------------------------------- 1 |
2 | convoy logo 3 |
4 |
5 |
6 | 7 | 8 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/saml/saml.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/public/saml/saml.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/saml/saml.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SamlComponent } from './saml.component'; 4 | 5 | describe('SamlComponent', () => { 6 | let component: SamlComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [ SamlComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(SamlComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/saml/saml.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { SamlService } from './saml.service'; 4 | 5 | describe('SamlService', () => { 6 | let service: SamlService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(SamlService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/signup/signup.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/public/signup/signup.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/signup/signup.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { SignupService } from './signup.service'; 4 | 5 | describe('SignupService', () => { 6 | let service: SignupService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(SignupService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/verify-email/verify-email.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/app/public/verify-email/verify-email.component.scss -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/verify-email/verify-email.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { VerifyEmailService } from './verify-email.service'; 4 | 5 | describe('VerifyEmailService', () => { 6 | let service: VerifyEmailService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(VerifyEmailService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/public/verify-email/verify-email.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpService } from 'src/app/services/http/http.service'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class VerifyEmailService { 8 | constructor(private http: HttpService) {} 9 | 10 | verifyEmail(token: string) { 11 | return new Promise(async (resolve, reject) => { 12 | try { 13 | const response = await this.http.request({ 14 | url: `/users/verify_email?token=${token}`, 15 | body: null, 16 | method: 'post' 17 | }); 18 | return resolve(response); 19 | } catch (error) { 20 | return reject(error); 21 | } 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/services/general/general.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { GeneralService } from './general.service'; 4 | 5 | describe('GeneralService', () => { 6 | let service: GeneralService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(GeneralService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/services/http/http.helper.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable({ 4 | providedIn: 'root' 5 | }) 6 | export class HttpHelperService { 7 | organisationId?: string; 8 | 9 | constructor() {} 10 | } 11 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/services/http/http.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { HttpService } from './http.service'; 4 | 5 | describe('HttpService', () => { 6 | let service: HttpService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(HttpService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/services/hubspot/hubspot.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { HubspotService } from './hubspot.service'; 4 | 5 | describe('PosthogService', () => { 6 | let service: HubspotService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(HubspotService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/services/licenses/licenses.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { LicensesService } from './licenses.service'; 4 | 5 | describe('LicensesService', () => { 6 | let service: LicensesService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(LicensesService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/app/services/rbac/rbac.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { RbacService } from './rbac.service'; 4 | 5 | describe('RbacService', () => { 6 | let service: RbacService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(RbacService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/.gitkeep -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/fonts/Menlo-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/fonts/Menlo-Regular.woff -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/fonts/inter/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7W0Q5n-wU.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/fonts/inter/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7W0Q5n-wU.woff2 -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/fonts/inter/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7W0Q5nw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/fonts/inter/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7W0Q5nw.woff2 -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/fonts/inter/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7W0Q5n-wU.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/fonts/inter/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7W0Q5n-wU.woff2 -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/fonts/inter/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7W0Q5n-wU.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/fonts/inter/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7W0Q5n-wU.woff2 -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/fonts/inter/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7W0Q5n-wU.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/fonts/inter/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7W0Q5n-wU.woff2 -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/fonts/inter/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7W0Q5n-wU.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/fonts/inter/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7W0Q5n-wU.woff2 -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/fonts/inter/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7W0Q5n-wU.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/fonts/inter/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7W0Q5n-wU.woff2 -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/Loader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/Loader.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/add-circlar-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/amqp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/amqp.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/angle-arrow-left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/button-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/button-loader.gif -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/checkbox-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/checkmark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/clock.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/close icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/close-icon-black.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/doc-icon-primary.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/download.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/enter-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/enter-icon.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/error-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/events-log-empty-state.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/events-log-empty-state.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/file.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/filter.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/filter.gif -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/github.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/go.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/go.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/google.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/inherit-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/js.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/js.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/kafka.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/kafka.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/loader.gif -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/new-empty-state.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/new-empty-state.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/new-success.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/new-success.gif -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/page-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/page-loader.gif -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/php.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/portal-link-empty-state.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/portal-link-empty-state.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/primary-info-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/public-layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/public-layout.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/python.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/rotate-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/ruby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/ruby.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/shopify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/shopify.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/sources-empty-state.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/sources-empty-state.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/sqs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/sqs.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/subscriptions-empty-state.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/subscriptions-empty-state.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/success.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/success.gif -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/success.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/teams-empty-state.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/teams-empty-state.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/twitter.png -------------------------------------------------------------------------------- /web/ui/dashboard/src/assets/img/warning.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/assets/img/warning.gif -------------------------------------------------------------------------------- /web/ui/dashboard/src/content/sdks/go/Add Endpoint.md: -------------------------------------------------------------------------------- 1 | ### Create Endpoint 2 | 3 | After setting up Convoy, you'll need to create an endpoint. An endpoint represents a target URL to receive events. 4 | 5 | ```go[example] 6 | endpoint, err := c.Endpoints.Create(&Convoy.CreateEndpointRequest{ 7 | Name: "Endpoint name", 8 | URL: "http://localhost:8081", 9 | Description: "Some description", 10 | }, nil) 11 | 12 | if err != nil { 13 | log.Fatal("failed to create endpoint \n", err) 14 | } 15 | ``` 16 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/content/sdks/go/Installation.md: -------------------------------------------------------------------------------- 1 | ### Installation 2 | 3 | Install convoy-go with 4 | 5 | ```bash[terminal] 6 | $ go get github.com/frain-dev/convoy-go 7 | ``` 8 | 9 | ### Configuration 10 | 11 | ```go[example] 12 | import ( 13 | convoy "github.com/frain-dev/convoy-go" 14 | ) 15 | 16 | c := convoy.New(convoy.Options{ 17 | APIKey: "your_api_key", 18 | }) 19 | ``` 20 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/content/sdks/go/Send Event.md: -------------------------------------------------------------------------------- 1 | ### Sending an Event 2 | 3 | To send an event, you'll need the `uid` from the endpoint we created earlier. 4 | 5 | ```go[example] 6 | event, err := c.Events.Create(&convoy.CreateEventRequest{ 7 | EndpointID: endpoint.UID, 8 | EventType: "test.customer.event", 9 | Data: []byte(`{"event_type": "test.event", "data": { "Hello": "World", "Test": "Data" }}`), 10 | }, nil) 11 | 12 | if err != nil { 13 | log.Fatal("failed to create event \n", err) 14 | } 15 | ``` 16 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/content/sdks/js/Add Endpoint.md: -------------------------------------------------------------------------------- 1 | ### Create Endpoint 2 | 3 | After setting up Convoy, you'll need to create an endpoint. An endpoint represents a target URL to receive events. 4 | 5 | ```js[example] 6 | try { 7 | const endpointData = { 8 | name: "Endpoint name", 9 | url: "https://0d87-102-89-2-172.ngrok.io", 10 | description: "Default Endpoint", 11 | secret: "endpoint-secret", 12 | events: ["*"], 13 | }; 14 | 15 | const response = await convoy.endpoints.create(endpointData); 16 | } catch (error) { 17 | console.log(error); 18 | } 19 | ``` 20 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/content/sdks/js/Installation.md: -------------------------------------------------------------------------------- 1 | ### Installation 2 | 3 | Install convoy.js with 4 | 5 | ```bash[terminal] 6 | $ npm install convoy.js 7 | ``` 8 | 9 | ### Configuration 10 | 11 | Next, require the `convoy` module and setup with your auth credentials. 12 | 13 | ```js[example] 14 | const { Convoy } = require("convoy.js"); 15 | const convoy = new Convoy({ api_key: "your_api_key" }); 16 | ``` 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/content/sdks/js/Send Event.md: -------------------------------------------------------------------------------- 1 | ### Sending an Event 2 | 3 | To send an event, you'll need the `uid` from the endpoint we created earlier. 4 | 5 | ```js[example] 6 | try { 7 | const eventData = { 8 | endpoint_id: endpointId, 9 | event_type: "payment.success", 10 | data: { 11 | event: "payment.success", 12 | data: { 13 | status: "Completed", 14 | description: "Transaction Successful", 15 | userID: "test_user_id808", 16 | }, 17 | }, 18 | }; 19 | 20 | const response = await convoy.events.create(eventData); 21 | } catch (error) { 22 | console.log(error); 23 | } 24 | ``` 25 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/content/sdks/php/Add Endpoint.md: -------------------------------------------------------------------------------- 1 | ### Create Endpoint 2 | 3 | After setting up Convoy, you'll need to create an endpoint. An endpoint represents a target URL to receive events. 4 | 5 | ```php[example] 6 | $endpointData = [ 7 | name: "Endpoint name", 8 | "url" => "https://0d87-102-89-2-172.ngrok.io", 9 | "description" => "Default Endpoint", 10 | "secret" => "endpoint-secret", 11 | "events" => ["*"] 12 | ] 13 | 14 | $response = $convoy->endpoints()->create($endpointData); 15 | ``` 16 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/content/sdks/php/Installation.md: -------------------------------------------------------------------------------- 1 | ### Installation 2 | 3 | To install the package, you will need to be using Composer in your project. 4 | 5 | To get started quickly, 6 | 7 | ```bash[terminal] 8 | $ composer require frain/convoy symfony/http-client nyholm/psr7 9 | ``` 10 | 11 | ### Configuration 12 | 13 | Next, import the `convoy` module and setup with your auth credentials. 14 | 15 | ```php[example] 16 | use Convoy\Convoy; 17 | 18 | $convoy = new Convoy(["api_key" => "your_api_key"]); 19 | ``` 20 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/content/sdks/php/Send Event.md: -------------------------------------------------------------------------------- 1 | ### Sending an Event 2 | 3 | To send an event, you'll need the `uid` from the endpoint we created earlier. 4 | 5 | ```php[example] 6 | $eventData = [ 7 | "endpoint_id" => $endpointId, 8 | "event_type" => "payment.success", 9 | "data" => [ 10 | "event" => "payment.success", 11 | "data" => [ 12 | "status" => "Completed", 13 | "description" => "Transaction Successful", 14 | "userID" => "test_user_id808" 15 | ] 16 | ] 17 | ]; 18 | 19 | $response = $convoy->events()->create($eventData); 20 | ``` 21 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/content/sdks/python/Add Endpoint.md: -------------------------------------------------------------------------------- 1 | ### Create Endpoint 2 | 3 | After setting up Convoy, you'll need to create an endpoint. An endpoint represents a target URL to receive events. 4 | 5 | ```python[example] 6 | endpointData = { 7 | name: "Endpoint name", 8 | "url": "https://0d87-102-89-2-172.ngrok.io", 9 | "description": "Default Endpoint", 10 | "secret": "endpoint-secret", 11 | "events": ["*"], 12 | } 13 | 14 | (response, status) = convoy.endpoint.create({}, endpointData) 15 | ``` 16 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/content/sdks/python/Installation.md: -------------------------------------------------------------------------------- 1 | ### Installation 2 | 3 | Install convoy-python with 4 | 5 | ```bash[terminal] 6 | $ pip install convoy-python 7 | ``` 8 | 9 | ### Configuration 10 | 11 | Next, import the `convoy` module and setup with your auth credentials. 12 | 13 | ```python[example] 14 | from convoy import Convoy 15 | convoy = Convoy({"api_key":"your_api_key"}) 16 | ``` 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/content/sdks/python/Send Event.md: -------------------------------------------------------------------------------- 1 | ### Sending an Event 2 | 3 | To send an event, you'll need the `uid` of the endpoint we created in the earlier section. 4 | 5 | ```python[example] 6 | eventData = { 7 | "endpoint_id": endpointId, 8 | "event_type": "payment.success", 9 | "data": { 10 | "event": "payment.success", 11 | "data": { 12 | "status": "Completed", 13 | "description": "Transaction Successful", 14 | "userID": "test_user_id808", 15 | }, 16 | }, 17 | } 18 | 19 | (response, status) = convoy.event.create({}, eventData) 20 | ``` 21 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/content/sdks/ruby/Add Endpoint.md: -------------------------------------------------------------------------------- 1 | ### Create Endpoint 2 | 3 | After setting up Convoy, you'll need to create an endpoint. An endpoint represents a target URL to receive events. 4 | 5 | ```ruby[example] 6 | endpoint = Convoy::Endpoint.new( 7 | data: { 8 | name: "Endpoint name", 9 | "description": "Endpoint One", 10 | "http_timeout": "1m", 11 | "url": "https://webhook.site/73932854-a20e-4d04-a151-d5952e873abd" 12 | } 13 | ) 14 | 15 | endpoint_response = endpoint.save 16 | ``` 17 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/content/sdks/ruby/Installation.md: -------------------------------------------------------------------------------- 1 | ### Installation 2 | 3 | Add this line to your application's Gemfile: 4 | 5 | ```console[terminal] 6 | $ gem 'convoy' 7 | ``` 8 | 9 | And then execute: 10 | 11 | ```console[terminal] 12 | $ bundle install 13 | ``` 14 | 15 | Or install it yourself as: 16 | 17 | ```console[terminal] 18 | $ gem install convoy 19 | ``` 20 | 21 | ### Configuration 22 | 23 | ```ruby[example] 24 | require 'convoy' 25 | 26 | Convoy.ssl = true 27 | Convoy.api_key = "CO.M0aBe..." 28 | Convoy.path_version = "v1" 29 | Convoy.base_uri = "https://dashboard.getconvoy.io/api" 30 | ``` 31 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/content/sdks/ruby/Send Event.md: -------------------------------------------------------------------------------- 1 | ### Send an Event 2 | 3 | Now let's send an event. 4 | 5 | ```ruby[example] 6 | event = Convoy::Event.new( 7 | data: { 8 | endpoint_id: endpoint_id, 9 | event_type: "wallet.created", 10 | data: { 11 | status: "completed", 12 | event_type: "wallet.created", 13 | description: "transaction successful" 14 | } 15 | } 16 | ) 17 | 18 | event_response = event.save 19 | ``` 20 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/environments/environment.ee.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | posthog: 'phc_lPJnjN5hrM8Dh7kgujIccs2xnGL2lmRv6UdOmOTCqEc', 4 | enterprise: true 5 | }; 6 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | posthog: 'phc_lPJnjN5hrM8Dh7kgujIccs2xnGL2lmRv6UdOmOTCqEc', 4 | enterprise: false 5 | }; 6 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frain-dev/convoy/26aa8aa67e85f63c8b73fa68465157ad870c47b7/web/ui/dashboard/src/favicon.ico -------------------------------------------------------------------------------- /web/ui/dashboard/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/stories/badge/Badge.stories.ts: -------------------------------------------------------------------------------- 1 | import { Story, Meta } from '@storybook/angular/types-6-0'; 2 | import { BadgeComponent } from '../../app/components/badge/badge.component'; 3 | 4 | export default { 5 | title: 'Example/Badge', 6 | component: BadgeComponent, 7 | argTypes: { 8 | text: { 9 | control: { type: 'text' } 10 | }, 11 | texture: { 12 | options: ['deep', 'light'], 13 | control: { type: 'select' }, 14 | defaultValue: 'light' 15 | } 16 | } 17 | } as Meta; 18 | 19 | const Template: Story = (args: BadgeComponent) => ({ 20 | props: args 21 | }); 22 | 23 | export const Base = Template.bind({}); 24 | Base.args = { 25 | text: 'org a', 26 | texture: 'light' 27 | }; 28 | -------------------------------------------------------------------------------- /web/ui/dashboard/src/stories/card/Card.stories.ts: -------------------------------------------------------------------------------- 1 | import { Story, Meta } from '@storybook/angular/types-6-0'; 2 | import { CardComponent } from '../../app/components/card/card.component'; 3 | 4 | export default { 5 | title: 'Example/Card', 6 | component: CardComponent, 7 | argTypes: { 8 | class: { 9 | control: { type: 'text' } 10 | } 11 | } 12 | } as Meta; 13 | 14 | const Template: Story = (args: CardComponent) => ({ 15 | template: `{{ngContent}}`, 16 | props: args 17 | }); 18 | 19 | export const Base = Template.bind({}); 20 | Base.args = { 21 | ngContent: 'This is convoy card', 22 | class: 'p-5' 23 | } as Partial; 24 | -------------------------------------------------------------------------------- /web/ui/dashboard/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": ["src/main.ts", "src/polyfills.ts"], 8 | "include": ["src/**/*.d.ts"], 9 | "exclude": ["**/*.stories.*"] 10 | } 11 | -------------------------------------------------------------------------------- /web/ui/dashboard/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /worker/task/process_dead_letters.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | import "github.com/frain-dev/convoy/queue" 4 | 5 | func ProcessDeadLetters(job *queue.Job) { 6 | 7 | } 8 | --------------------------------------------------------------------------------