From 484f1a8a13b3a365d5b8fb272a9b451f9c4e74da Mon Sep 17 00:00:00 2001 From: Nimish <85357445+nimish-ks@users.noreply.github.com> Date: Thu, 18 Jul 2024 14:18:04 +0530 Subject: [PATCH] feat: railway integration (#297) * feat: railway integration --------- Co-authored-by: rohan-chaturvedi --- .github/pull_request_template.md | 4 +- .vscode/settings.json | 3 + ...0070_alter_providercredentials_provider.py | 18 + .../0071_alter_environmentsync_service.py | 18 + backend/api/services.py | 15 + backend/api/tasks.py | 94 +++++ backend/api/utils/syncing/railway/main.py | 179 ++++++++ backend/backend/graphene/mutations/syncing.py | 76 ++++ backend/backend/graphene/queries/syncing.py | 11 + backend/backend/schema.py | 10 + frontend/apollo/gql.ts | 10 + frontend/apollo/graphql.ts | 69 ++++ frontend/apollo/schema.graphql | 29 ++ .../app/[team]/apps/[app]/syncing/page.tsx | 13 +- .../syncing/CreateProviderCredentials.tsx | 2 +- .../CreateProviderCredentialsDialog.tsx | 2 +- .../components/syncing/CreateSyncDialog.tsx | 3 + frontend/components/syncing/ProviderIcon.tsx | 13 +- .../syncing/Railway/CreateRailwaySync.tsx | 383 ++++++++++++++++++ frontend/components/syncing/ServiceInfo.tsx | 12 +- .../railway/createRailwayEnvironmentSync.gql | 33 ++ .../queries/syncing/railway/getProjects.gql | 14 + 22 files changed, 997 insertions(+), 14 deletions(-) create mode 100644 backend/api/migrations/0070_alter_providercredentials_provider.py create mode 100644 backend/api/migrations/0071_alter_environmentsync_service.py create mode 100644 backend/api/utils/syncing/railway/main.py create mode 100644 frontend/components/syncing/Railway/CreateRailwaySync.tsx create mode 100644 frontend/graphql/mutations/syncing/railway/createRailwayEnvironmentSync.gql create mode 100644 frontend/graphql/queries/syncing/railway/getProjects.gql diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index c3c7d5a5..d28b5138 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -38,8 +38,6 @@ - [ ] Ensure linting passes (code style checks)? - [ ] Update dependencies and lockfiles (if required) +- [ ] Regenerate graphql schema and types (if required) - [ ] Verify the app builds locally? - [ ] Manually test the changes on different browsers/devices? - - - diff --git a/.vscode/settings.json b/.vscode/settings.json index 14ae62f2..1f25d797 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -25,5 +25,8 @@ "[python]": { "editor.defaultFormatter": "ms-python.black-formatter", "editor.formatOnSave": true + }, + "[graphql]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" } // Don't run prettier for files listed in .gitignore } diff --git a/backend/api/migrations/0070_alter_providercredentials_provider.py b/backend/api/migrations/0070_alter_providercredentials_provider.py new file mode 100644 index 00000000..bf20fc7f --- /dev/null +++ b/backend/api/migrations/0070_alter_providercredentials_provider.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2024-07-16 07:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0069_activatedphaselicense'), + ] + + operations = [ + migrations.AlterField( + model_name='providercredentials', + name='provider', + field=models.CharField(choices=[('cloudflare', 'Cloudflare'), ('aws', 'AWS'), ('github', 'GitHub'), ('gitlab', 'GitLab'), ('hashicorp_vault', 'Hashicorp Vault'), ('hashicorp_nomad', 'Hashicorp Nomad'), ('railway', 'Railway')], max_length=50), + ), + ] diff --git a/backend/api/migrations/0071_alter_environmentsync_service.py b/backend/api/migrations/0071_alter_environmentsync_service.py new file mode 100644 index 00000000..5ffc6990 --- /dev/null +++ b/backend/api/migrations/0071_alter_environmentsync_service.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2024-07-16 07:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0070_alter_providercredentials_provider'), + ] + + operations = [ + migrations.AlterField( + model_name='environmentsync', + name='service', + field=models.CharField(choices=[('cloudflare_pages', 'Cloudflare Pages'), ('aws_secrets_manager', 'AWS Secrets Manager'), ('github_actions', 'GitHub Actions'), ('gitlab_ci', 'GitLab CI'), ('hashicorp_vault', 'Hashicorp Vault'), ('hashicorp_nomad', 'Hashicorp Nomad'), ('railway', 'Railway')], max_length=50), + ), + ] diff --git a/backend/api/services.py b/backend/api/services.py index 2ca91beb..5d388a1a 100644 --- a/backend/api/services.py +++ b/backend/api/services.py @@ -54,6 +54,14 @@ class Providers: "auth_scheme": "token", } + RAILWAY = { + "id": "railway", + "name": "Railway", + "expected_credentials": ["api_token"], + "optional_credentials": [], + "auth_scheme": "token", + } + @classmethod def get_provider_choices(cls): return [ @@ -119,6 +127,13 @@ class ServiceConfig: "resource_type": "path", } + RAILWAY = { + "id": "railway", + "name": "Railway", + "provider": Providers.RAILWAY, + "resource_type": "environment", + } + @classmethod def get_service_choices(cls): return [ diff --git a/backend/api/tasks.py b/backend/api/tasks.py index 75a64e0e..b1c82e5e 100644 --- a/backend/api/tasks.py +++ b/backend/api/tasks.py @@ -9,6 +9,7 @@ from api.utils.syncing.vault.main import sync_vault_secrets from api.utils.syncing.nomad.main import sync_nomad_secrets from api.utils.syncing.gitlab.main import sync_gitlab_secrets +from api.utils.syncing.railway.main import sync_railway_secrets from .utils.syncing.cloudflare.pages import ( get_cf_pages_credentials, sync_cloudflare_secrets, @@ -83,6 +84,15 @@ def trigger_sync_tasks(env_sync): EnvironmentSyncEvent.objects.create(id=job_id, env_sync=env_sync) + elif env_sync.service == ServiceConfig.RAILWAY["id"]: + env_sync.status = EnvironmentSync.IN_PROGRESS + env_sync.save() + + job = perform_railway_sync.delay(env_sync) + job_id = job.get_id() + + EnvironmentSyncEvent.objects.create(id=job_id, env_sync=env_sync) + # try and cancel running or queued jobs for this sync def cancel_sync_tasks(env_sync): @@ -666,3 +676,87 @@ def perform_gitlab_sync(environment_sync): environment_sync.last_sync = timezone.now() environment_sync.status = EnvironmentSync.FAILED environment_sync.save() + + +@job("default", timeout=3600) +def perform_railway_sync(environment_sync): + try: + EnvironmentSync = apps.get_model("api", "EnvironmentSync") + EnvironmentSyncEvent = apps.get_model("api", "EnvironmentSyncEvent") + + secrets = get_environment_secrets( + environment_sync.environment, environment_sync.path + ) + + if environment_sync.authentication is None: + sync_data = ( + False, + {"message": "No authentication credentials for this sync"}, + ) + raise Exception("No authentication credentials for this sync") + + railway_sync_options = environment_sync.options + + railway_project = railway_sync_options.get("project") + railway_environment = railway_sync_options.get("environment") + railway_service = railway_sync_options.get("service") + + success, sync_data = sync_railway_secrets( + secrets, + environment_sync.authentication.id, + railway_project["id"], + railway_environment["id"], + railway_service["id"] if railway_service is not None else None, + ) + + sync_event = ( + EnvironmentSyncEvent.objects.filter(env_sync=environment_sync) + .order_by("-created_at") + .first() + ) + + if success: + sync_event.status = EnvironmentSync.COMPLETED + sync_event.completed_at = timezone.now() + sync_event.meta = sync_data + sync_event.save() + + environment_sync.last_sync = timezone.now() + environment_sync.status = EnvironmentSync.COMPLETED + environment_sync.save() + + else: + sync_event.status = EnvironmentSync.FAILED + sync_event.completed_at = timezone.now() + sync_event.meta = sync_data + sync_event.save() + + environment_sync.last_sync = timezone.now() + environment_sync.status = EnvironmentSync.FAILED + environment_sync.save() + + except JobTimeoutException: + # Handle timeout exception + sync_event.status = EnvironmentSync.TIMED_OUT + sync_event.completed_at = timezone.now() + sync_event.save() + + environment_sync.last_sync = timezone.now() + environment_sync.status = EnvironmentSync.TIMED_OUT + environment_sync.save() + raise # Re-raise the JobTimeoutException + + except Exception as ex: + print(f"EXCEPTION {ex}") + sync_event.status = EnvironmentSync.FAILED + sync_event.completed_at = timezone.now() + + try: + sync_event.meta = sync_data + except: + pass + sync_event.save() + + environment_sync.last_sync = timezone.now() + environment_sync.status = EnvironmentSync.FAILED + environment_sync.save() diff --git a/backend/api/utils/syncing/railway/main.py b/backend/api/utils/syncing/railway/main.py new file mode 100644 index 00000000..e2850ce9 --- /dev/null +++ b/backend/api/utils/syncing/railway/main.py @@ -0,0 +1,179 @@ +import requests +import graphene + +from api.utils.syncing.auth import get_credentials + + +class RailwayServiceType(graphene.ObjectType): + id = graphene.ID(required=True) + name = graphene.String(required=True) + + +class RailwayEnvironmentType(graphene.ObjectType): + id = graphene.ID(required=True) + name = graphene.String(required=True) + project_id = graphene.ID(required=True) + + +class RailwayProjectType(graphene.ObjectType): + id = graphene.ID(required=True) + name = graphene.String(required=True) + environments = graphene.List( + graphene.NonNull(RailwayEnvironmentType), required=True + ) + services = graphene.List(graphene.NonNull(RailwayServiceType), required=True) + + +RAILWAY_API_URL = "https://backboard.railway.app/graphql/v2" + + +def get_headers(api_token): + return {"Authorization": f"Bearer {api_token}", "Content-Type": "application/json"} + + +def fetch_railway_projects(credential_id): + credentials = get_credentials(credential_id) + api_token = credentials.get("api_token") + + headers = { + "Authorization": f"Bearer {api_token}", + "Content-Type": "application/json", + } + + query = """ + query { + projects { + edges { + node { + id + name + environments { + edges { + node { + id + name + } + } + } + services { + edges { + node { + id + name + } + } + } + } + } + } + } + """ + + response = requests.post(RAILWAY_API_URL, json={"query": query}, headers=headers) + response.raise_for_status() + data = response.json() + + if "errors" in data: + raise Exception(data["errors"]) + + projects = [] + for edge in data["data"]["projects"]["edges"]: + project = edge["node"] + environments = [ + env_edge["node"] for env_edge in project["environments"]["edges"] + ] + services = [env_edge["node"] for env_edge in project["services"]["edges"]] + project["environments"] = environments + project["services"] = services + projects.append(project) + + return projects + + +def create_environment(name, api_token): + headers = get_headers(api_token) + + mutation = """ + mutation($name: String!) { + createEnvironment(input: { name: $name }) { + environment { + id + name + } + } + } + """ + variables = {"name": name} + response = requests.post( + RAILWAY_API_URL, + json={"query": mutation, "variables": variables}, + headers=headers, + ) + response.raise_for_status() + data = response.json() + + if "errors" in data: + raise Exception(data["errors"]) + + environment = data["data"]["createEnvironment"]["environment"] + return environment + + +def sync_railway_secrets( + secrets, credential_id, project_id, railway_environment_id, service_id=None +): + + try: + credentials = get_credentials(credential_id) + api_token = credentials.get("api_token") + + headers = { + "Authorization": f"Bearer {api_token}", + "Content-Type": "application/json", + "Accept-Encoding": "application/json", + } + + # Prepare the secrets to the format expected by Railway + formatted_secrets = {k: v for k, v, _ in secrets} + + # Build the mutation query + mutation = """ + mutation UpsertVariables($input: VariableCollectionUpsertInput!) { + variableCollectionUpsert(input: $input) + } + """ + variables = { + "input": { + "projectId": project_id, + "environmentId": railway_environment_id, + "replace": True, + "variables": formatted_secrets, + } + } + + # Optionally add serviceId if provided + if service_id: + variables["input"]["serviceId"] = service_id + + # Make the request to Railway API + response = requests.post( + RAILWAY_API_URL, + json={"query": mutation, "variables": variables}, + headers=headers, + ) + + data = response.json() + + response.raise_for_status() + + if "errors" in data: + raise Exception(data["errors"]) + + else: + return True, { + "response_code": response.status_code, + "message": "Successfully synced secrets.", + } + + except Exception as e: + return False, {"message": f"Error syncing secrets: {str(e)}"} diff --git a/backend/backend/graphene/mutations/syncing.py b/backend/backend/graphene/mutations/syncing.py index 5cf5ef36..64e6044c 100644 --- a/backend/backend/graphene/mutations/syncing.py +++ b/backend/backend/graphene/mutations/syncing.py @@ -21,6 +21,11 @@ from api.services import ServiceConfig +class RailwayResourceInput(graphene.InputObjectType): + id = graphene.ID(required=True) + name = graphene.String(required=True) + + class InitEnvSync(graphene.Mutation): class Arguments: app_id = graphene.ID() @@ -434,6 +439,77 @@ def mutate( return CreateGitLabCISync(sync=sync) +class CreateRailwaySync(graphene.Mutation): + class Arguments: + env_id = graphene.ID() + path = graphene.String() + credential_id = graphene.ID() + railway_project = graphene.Argument(RailwayResourceInput) + railway_environment = graphene.Argument(RailwayResourceInput) + railway_service = graphene.Argument(RailwayResourceInput, required=False) + + sync = graphene.Field(EnvironmentSyncType) + + @classmethod + def mutate( + cls, + root, + info, + env_id, + path, + credential_id, + railway_project, + railway_environment, + railway_service=None, + ): + service_id = "railway" + service_config = ServiceConfig.get_service_config(service_id) + + env = Environment.objects.get(id=env_id) + + if not ServerEnvironmentKey.objects.filter(environment=env).exists(): + raise GraphQLError("Syncing is not enabled for this environment!") + + if not user_can_access_app(info.context.user.userId, env.app.id): + raise GraphQLError("You don't have access to this app") + + sync_options = { + "project": {"id": railway_project.id, "name": railway_project.name}, + "environment": { + "id": railway_environment.id, + "name": railway_environment.name, + }, + } + + if railway_service: + sync_options["service"] = { + "id": railway_service.id, + "name": railway_service.name, + } + + existing_syncs = EnvironmentSync.objects.filter( + environment__app_id=env.app.id, service=service_id, deleted_at=None + ) + + for es in existing_syncs: + if es.options == sync_options: + raise GraphQLError( + f"A sync already exists for this Railway environment!" + ) + + sync = EnvironmentSync.objects.create( + environment=env, + path=normalize_path_string(path), + service=service_id, + options=sync_options, + authentication_id=credential_id, + ) + + trigger_sync_tasks(sync) + + return CreateRailwaySync(sync=sync) + + class DeleteSync(graphene.Mutation): class Arguments: sync_id = graphene.ID() diff --git a/backend/backend/graphene/queries/syncing.py b/backend/backend/graphene/queries/syncing.py index fcdf3101..a5d33128 100644 --- a/backend/backend/graphene/queries/syncing.py +++ b/backend/backend/graphene/queries/syncing.py @@ -21,6 +21,9 @@ from api.utils.syncing.vault.main import test_vault_creds from api.utils.syncing.nomad.main import test_nomad_creds from api.utils.syncing.gitlab.main import list_gitlab_groups, list_gitlab_projects +from api.utils.syncing.railway.main import ( + fetch_railway_projects, +) from backend.graphene.types import ProviderType, ServiceType from graphql import GraphQLError @@ -145,6 +148,14 @@ def resolve_gitlab_groups(root, info, credential_id): raise GraphQLError(f"Error listing GitLab groups: {str(ex)}") +def resolve_railway_projects(root, info, credential_id): + try: + projects = fetch_railway_projects(credential_id) + return projects + except Exception as ex: + raise GraphQLError(f"Error listing Railway environments: {str(ex)}") + + def resolve_syncs(root, info, app_id=None, env_id=None, org_id=None): # If both app_id and env_id are provided if app_id and env_id: diff --git a/backend/backend/schema.py b/backend/backend/schema.py index ea4dc930..2edb7126 100644 --- a/backend/backend/schema.py +++ b/backend/backend/schema.py @@ -3,6 +3,7 @@ from api.utils.syncing.github.actions import GitHubRepoType from api.utils.syncing.vault.main import VaultMountType from api.utils.syncing.gitlab.main import GitLabGroupType, GitLabProjectType +from api.utils.syncing.railway.main import RailwayEnvironmentType, RailwayProjectType from .graphene.mutations.lockbox import CreateLockboxMutation from .graphene.queries.syncing import ( resolve_aws_secret_manager_secrets, @@ -19,6 +20,7 @@ resolve_env_syncs, resolve_test_vault_creds, resolve_test_nomad_creds, + resolve_railway_projects, ) from .graphene.queries.quotas import resolve_organisation_plan from .graphene.queries.license import resolve_license, resolve_organisation_license @@ -48,6 +50,7 @@ CreateGitLabCISync, CreateNomadSync, CreateProviderCredentials, + CreateRailwaySync, CreateVaultSync, DeleteProviderCredentials, DeleteSync, @@ -247,6 +250,8 @@ class Query(graphene.ObjectType): gitlab_projects = graphene.List(GitLabProjectType, credential_id=graphene.ID()) gitlab_groups = graphene.List(GitLabGroupType, credential_id=graphene.ID()) + railway_projects = graphene.List(RailwayProjectType, credential_id=graphene.ID()) + test_vault_creds = graphene.Field(graphene.Boolean, credential_id=graphene.ID()) test_nomad_creds = graphene.Field(graphene.Boolean, credential_id=graphene.ID()) @@ -276,6 +281,8 @@ class Query(graphene.ObjectType): resolve_gitlab_projects = resolve_gitlab_projects resolve_gitlab_groups = resolve_gitlab_groups + resolve_railway_projects = resolve_railway_projects + resolve_test_vault_creds = resolve_test_vault_creds resolve_test_nomad_creds = resolve_test_nomad_creds @@ -720,6 +727,9 @@ class Mutation(graphene.ObjectType): # GitLab create_gitlab_ci_sync = CreateGitLabCISync.Field() + # Railway + create_railway_sync = CreateRailwaySync.Field() + create_user_token = CreateUserTokenMutation.Field() delete_user_token = DeleteUserTokenMutation.Field() diff --git a/frontend/apollo/gql.ts b/frontend/apollo/gql.ts index 0c46c7e6..21ae924e 100644 --- a/frontend/apollo/gql.ts +++ b/frontend/apollo/gql.ts @@ -50,6 +50,7 @@ const documents = { "mutation CreateNewGitlabCiSync($envId: ID!, $path: String!, $credentialId: ID!, $resourcePath: String!, $resourceId: String!, $isGroup: Boolean!, $isMasked: Boolean!, $isProtected: Boolean!) {\n createGitlabCiSync(\n envId: $envId\n path: $path\n credentialId: $credentialId\n resourcePath: $resourcePath\n resourceId: $resourceId\n isGroup: $isGroup\n masked: $isMasked\n protected: $isProtected\n ) {\n sync {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n isActive\n lastSync\n createdAt\n }\n }\n}": types.CreateNewGitlabCiSyncDocument, "mutation InitAppSyncing($appId: ID!, $envKeys: [EnvironmentKeyInput]) {\n initEnvSync(appId: $appId, envKeys: $envKeys) {\n app {\n id\n sseEnabled\n }\n }\n}": types.InitAppSyncingDocument, "mutation CreateNewNomadSync($envId: ID!, $path: String!, $nomadPath: String!, $nomadNamespace: String!, $credentialId: ID!) {\n createNomadSync(\n envId: $envId\n path: $path\n nomadPath: $nomadPath\n nomadNamespace: $nomadNamespace\n credentialId: $credentialId\n ) {\n sync {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n isActive\n lastSync\n createdAt\n }\n }\n}": types.CreateNewNomadSyncDocument, + "mutation CreateNewRailwaySync($envId: ID!, $path: String!, $credentialId: ID!, $railwayProject: RailwayResourceInput!, $railwayEnvironment: RailwayResourceInput!, $railwayService: RailwayResourceInput) {\n createRailwaySync(\n envId: $envId\n path: $path\n credentialId: $credentialId\n railwayProject: $railwayProject\n railwayEnvironment: $railwayEnvironment\n railwayService: $railwayService\n ) {\n sync {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n isActive\n lastSync\n createdAt\n }\n }\n}": types.CreateNewRailwaySyncDocument, "mutation SaveNewProviderCreds($orgId: ID!, $provider: String!, $name: String!, $credentials: JSONString!) {\n createProviderCredentials(\n orgId: $orgId\n provider: $provider\n name: $name\n credentials: $credentials\n ) {\n credential {\n id\n }\n }\n}": types.SaveNewProviderCredsDocument, "mutation ToggleSync($syncId: ID!) {\n toggleSyncActive(syncId: $syncId) {\n ok\n }\n}": types.ToggleSyncDocument, "mutation TriggerEnvSync($syncId: ID!) {\n triggerSync(syncId: $syncId) {\n sync {\n status\n }\n }\n}": types.TriggerEnvSyncDocument, @@ -93,6 +94,7 @@ const documents = { "query GetGithubRepos($credentialId: ID!) {\n githubRepos(credentialId: $credentialId) {\n name\n owner\n type\n }\n}": types.GetGithubReposDocument, "query GetGitLabResources($credentialId: ID!) {\n gitlabProjects(credentialId: $credentialId) {\n id\n name\n namespace {\n name\n fullPath\n }\n pathWithNamespace\n webUrl\n }\n gitlabGroups(credentialId: $credentialId) {\n id\n fullName\n fullPath\n webUrl\n }\n}": types.GetGitLabResourcesDocument, "query TestNomadAuth($credentialId: ID!) {\n testNomadCreds(credentialId: $credentialId)\n}": types.TestNomadAuthDocument, + "query GetRailwayProjects($credentialId: ID!) {\n railwayProjects(credentialId: $credentialId) {\n id\n name\n environments {\n id\n name\n }\n services {\n id\n name\n }\n }\n}": types.GetRailwayProjectsDocument, "query TestVaultAuth($credentialId: ID!) {\n testVaultCreds(credentialId: $credentialId)\n}": types.TestVaultAuthDocument, "query GetUserTokens($organisationId: ID!) {\n userTokens(organisationId: $organisationId) {\n id\n name\n wrappedKeyShare\n createdAt\n expiresAt\n }\n}": types.GetUserTokensDocument, }; @@ -259,6 +261,10 @@ export function graphql(source: "mutation InitAppSyncing($appId: ID!, $envKeys: * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "mutation CreateNewNomadSync($envId: ID!, $path: String!, $nomadPath: String!, $nomadNamespace: String!, $credentialId: ID!) {\n createNomadSync(\n envId: $envId\n path: $path\n nomadPath: $nomadPath\n nomadNamespace: $nomadNamespace\n credentialId: $credentialId\n ) {\n sync {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n isActive\n lastSync\n createdAt\n }\n }\n}"): (typeof documents)["mutation CreateNewNomadSync($envId: ID!, $path: String!, $nomadPath: String!, $nomadNamespace: String!, $credentialId: ID!) {\n createNomadSync(\n envId: $envId\n path: $path\n nomadPath: $nomadPath\n nomadNamespace: $nomadNamespace\n credentialId: $credentialId\n ) {\n sync {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n isActive\n lastSync\n createdAt\n }\n }\n}"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "mutation CreateNewRailwaySync($envId: ID!, $path: String!, $credentialId: ID!, $railwayProject: RailwayResourceInput!, $railwayEnvironment: RailwayResourceInput!, $railwayService: RailwayResourceInput) {\n createRailwaySync(\n envId: $envId\n path: $path\n credentialId: $credentialId\n railwayProject: $railwayProject\n railwayEnvironment: $railwayEnvironment\n railwayService: $railwayService\n ) {\n sync {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n isActive\n lastSync\n createdAt\n }\n }\n}"): (typeof documents)["mutation CreateNewRailwaySync($envId: ID!, $path: String!, $credentialId: ID!, $railwayProject: RailwayResourceInput!, $railwayEnvironment: RailwayResourceInput!, $railwayService: RailwayResourceInput) {\n createRailwaySync(\n envId: $envId\n path: $path\n credentialId: $credentialId\n railwayProject: $railwayProject\n railwayEnvironment: $railwayEnvironment\n railwayService: $railwayService\n ) {\n sync {\n id\n environment {\n id\n name\n envType\n }\n serviceInfo {\n id\n name\n }\n isActive\n lastSync\n createdAt\n }\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -431,6 +437,10 @@ export function graphql(source: "query GetGitLabResources($credentialId: ID!) {\ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "query TestNomadAuth($credentialId: ID!) {\n testNomadCreds(credentialId: $credentialId)\n}"): (typeof documents)["query TestNomadAuth($credentialId: ID!) {\n testNomadCreds(credentialId: $credentialId)\n}"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "query GetRailwayProjects($credentialId: ID!) {\n railwayProjects(credentialId: $credentialId) {\n id\n name\n environments {\n id\n name\n }\n services {\n id\n name\n }\n }\n}"): (typeof documents)["query GetRailwayProjects($credentialId: ID!) {\n railwayProjects(credentialId: $credentialId) {\n id\n name\n environments {\n id\n name\n }\n services {\n id\n name\n }\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/frontend/apollo/graphql.ts b/frontend/apollo/graphql.ts index 52852455..c9995412 100644 --- a/frontend/apollo/graphql.ts +++ b/frontend/apollo/graphql.ts @@ -257,6 +257,11 @@ export type CreateProviderCredentials = { credential?: Maybe; }; +export type CreateRailwaySync = { + __typename?: 'CreateRailwaySync'; + sync?: Maybe; +}; + export type CreateSecretFolderMutation = { __typename?: 'CreateSecretFolderMutation'; folder?: Maybe; @@ -546,6 +551,7 @@ export type Mutation = { createOrganisationMember?: Maybe; createOverride?: Maybe; createProviderCredentials?: Maybe; + createRailwaySync?: Maybe; createSecret?: Maybe; createSecretFolder?: Maybe; createSecretTag?: Maybe; @@ -706,6 +712,16 @@ export type MutationCreateProviderCredentialsArgs = { }; +export type MutationCreateRailwaySyncArgs = { + credentialId?: InputMaybe; + envId?: InputMaybe; + path?: InputMaybe; + railwayEnvironment?: InputMaybe; + railwayProject?: InputMaybe; + railwayService?: InputMaybe; +}; + + export type MutationCreateSecretArgs = { secretData?: InputMaybe; }; @@ -1037,6 +1053,7 @@ export type Query = { organisationPlan?: Maybe; organisations?: Maybe>>; providers?: Maybe>>; + railwayProjects?: Maybe>>; savedCredentials?: Maybe>>; secretHistory?: Maybe>>; secretTags?: Maybe>>; @@ -1171,6 +1188,11 @@ export type QueryOrganisationPlanArgs = { }; +export type QueryRailwayProjectsArgs = { + credentialId?: InputMaybe; +}; + + export type QuerySavedCredentialsArgs = { orgId?: InputMaybe; }; @@ -1233,6 +1255,32 @@ export type QueryValidateInviteArgs = { inviteId?: InputMaybe; }; +export type RailwayEnvironmentType = { + __typename?: 'RailwayEnvironmentType'; + id: Scalars['ID']['output']; + name: Scalars['String']['output']; + projectId: Scalars['ID']['output']; +}; + +export type RailwayProjectType = { + __typename?: 'RailwayProjectType'; + environments: Array; + id: Scalars['ID']['output']; + name: Scalars['String']['output']; + services: Array; +}; + +export type RailwayResourceInput = { + id: Scalars['ID']['input']; + name: Scalars['String']['input']; +}; + +export type RailwayServiceType = { + __typename?: 'RailwayServiceType'; + id: Scalars['ID']['output']; + name: Scalars['String']['output']; +}; + export type ReadSecretMutation = { __typename?: 'ReadSecretMutation'; ok?: Maybe; @@ -1739,6 +1787,18 @@ export type CreateNewNomadSyncMutationVariables = Exact<{ export type CreateNewNomadSyncMutation = { __typename?: 'Mutation', createNomadSync?: { __typename?: 'CreateNomadSync', sync?: { __typename?: 'EnvironmentSyncType', id: string, isActive: boolean, lastSync?: any | null, createdAt?: any | null, environment: { __typename?: 'EnvironmentType', id: string, name: string, envType: ApiEnvironmentEnvTypeChoices }, serviceInfo?: { __typename?: 'ServiceType', id?: string | null, name?: string | null } | null } | null } | null }; +export type CreateNewRailwaySyncMutationVariables = Exact<{ + envId: Scalars['ID']['input']; + path: Scalars['String']['input']; + credentialId: Scalars['ID']['input']; + railwayProject: RailwayResourceInput; + railwayEnvironment: RailwayResourceInput; + railwayService?: InputMaybe; +}>; + + +export type CreateNewRailwaySyncMutation = { __typename?: 'Mutation', createRailwaySync?: { __typename?: 'CreateRailwaySync', sync?: { __typename?: 'EnvironmentSyncType', id: string, isActive: boolean, lastSync?: any | null, createdAt?: any | null, environment: { __typename?: 'EnvironmentType', id: string, name: string, envType: ApiEnvironmentEnvTypeChoices }, serviceInfo?: { __typename?: 'ServiceType', id?: string | null, name?: string | null } | null } | null } | null }; + export type SaveNewProviderCredsMutationVariables = Exact<{ orgId: Scalars['ID']['input']; provider: Scalars['String']['input']; @@ -2058,6 +2118,13 @@ export type TestNomadAuthQueryVariables = Exact<{ export type TestNomadAuthQuery = { __typename?: 'Query', testNomadCreds?: boolean | null }; +export type GetRailwayProjectsQueryVariables = Exact<{ + credentialId: Scalars['ID']['input']; +}>; + + +export type GetRailwayProjectsQuery = { __typename?: 'Query', railwayProjects?: Array<{ __typename?: 'RailwayProjectType', id: string, name: string, environments: Array<{ __typename?: 'RailwayEnvironmentType', id: string, name: string }>, services: Array<{ __typename?: 'RailwayServiceType', id: string, name: string }> } | null> | null }; + export type TestVaultAuthQueryVariables = Exact<{ credentialId: Scalars['ID']['input']; }>; @@ -2110,6 +2177,7 @@ export const CreateNewGhActionsSyncDocument = {"kind":"Document","definitions":[ export const CreateNewGitlabCiSyncDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateNewGitlabCiSync"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"envId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"path"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"resourcePath"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"resourceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isGroup"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isMasked"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isProtected"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createGitlabCiSync"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"envId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}},{"kind":"Argument","name":{"kind":"Name","value":"path"},"value":{"kind":"Variable","name":{"kind":"Name","value":"path"}}},{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}},{"kind":"Argument","name":{"kind":"Name","value":"resourcePath"},"value":{"kind":"Variable","name":{"kind":"Name","value":"resourcePath"}}},{"kind":"Argument","name":{"kind":"Name","value":"resourceId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"resourceId"}}},{"kind":"Argument","name":{"kind":"Name","value":"isGroup"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isGroup"}}},{"kind":"Argument","name":{"kind":"Name","value":"masked"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isMasked"}}},{"kind":"Argument","name":{"kind":"Name","value":"protected"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isProtected"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sync"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"environment"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"envType"}}]}},{"kind":"Field","name":{"kind":"Name","value":"serviceInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"lastSync"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]}}]} as unknown as DocumentNode; export const InitAppSyncingDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"InitAppSyncing"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"envKeys"}},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EnvironmentKeyInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"initEnvSync"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}},{"kind":"Argument","name":{"kind":"Name","value":"envKeys"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envKeys"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"app"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"sseEnabled"}}]}}]}}]}}]} as unknown as DocumentNode; export const CreateNewNomadSyncDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateNewNomadSync"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"envId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"path"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"nomadPath"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"nomadNamespace"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createNomadSync"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"envId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}},{"kind":"Argument","name":{"kind":"Name","value":"path"},"value":{"kind":"Variable","name":{"kind":"Name","value":"path"}}},{"kind":"Argument","name":{"kind":"Name","value":"nomadPath"},"value":{"kind":"Variable","name":{"kind":"Name","value":"nomadPath"}}},{"kind":"Argument","name":{"kind":"Name","value":"nomadNamespace"},"value":{"kind":"Variable","name":{"kind":"Name","value":"nomadNamespace"}}},{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sync"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"environment"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"envType"}}]}},{"kind":"Field","name":{"kind":"Name","value":"serviceInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"lastSync"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]}}]} as unknown as DocumentNode; +export const CreateNewRailwaySyncDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateNewRailwaySync"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"envId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"path"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"railwayProject"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RailwayResourceInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"railwayEnvironment"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RailwayResourceInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"railwayService"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RailwayResourceInput"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createRailwaySync"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"envId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}},{"kind":"Argument","name":{"kind":"Name","value":"path"},"value":{"kind":"Variable","name":{"kind":"Name","value":"path"}}},{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}},{"kind":"Argument","name":{"kind":"Name","value":"railwayProject"},"value":{"kind":"Variable","name":{"kind":"Name","value":"railwayProject"}}},{"kind":"Argument","name":{"kind":"Name","value":"railwayEnvironment"},"value":{"kind":"Variable","name":{"kind":"Name","value":"railwayEnvironment"}}},{"kind":"Argument","name":{"kind":"Name","value":"railwayService"},"value":{"kind":"Variable","name":{"kind":"Name","value":"railwayService"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sync"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"environment"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"envType"}}]}},{"kind":"Field","name":{"kind":"Name","value":"serviceInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"lastSync"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]}}]} as unknown as DocumentNode; export const SaveNewProviderCredsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SaveNewProviderCreds"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"provider"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentials"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSONString"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createProviderCredentials"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orgId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}}},{"kind":"Argument","name":{"kind":"Name","value":"provider"},"value":{"kind":"Variable","name":{"kind":"Name","value":"provider"}}},{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}},{"kind":"Argument","name":{"kind":"Name","value":"credentials"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentials"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"credential"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; export const ToggleSyncDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ToggleSync"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"syncId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"toggleSyncActive"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"syncId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"syncId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const TriggerEnvSyncDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"TriggerEnvSync"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"syncId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"triggerSync"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"syncId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"syncId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sync"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]}}]} as unknown as DocumentNode; @@ -2153,5 +2221,6 @@ export const GetServiceListDocument = {"kind":"Document","definitions":[{"kind": export const GetGithubReposDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetGithubRepos"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"githubRepos"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"owner"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]}}]} as unknown as DocumentNode; export const GetGitLabResourcesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetGitLabResources"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"gitlabProjects"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"namespace"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"fullPath"}}]}},{"kind":"Field","name":{"kind":"Name","value":"pathWithNamespace"}},{"kind":"Field","name":{"kind":"Name","value":"webUrl"}}]}},{"kind":"Field","name":{"kind":"Name","value":"gitlabGroups"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"fullPath"}},{"kind":"Field","name":{"kind":"Name","value":"webUrl"}}]}}]}}]} as unknown as DocumentNode; export const TestNomadAuthDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"TestNomadAuth"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"testNomadCreds"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}}]}]}}]} as unknown as DocumentNode; +export const GetRailwayProjectsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetRailwayProjects"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"railwayProjects"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"environments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"services"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; export const TestVaultAuthDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"TestVaultAuth"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"testVaultCreds"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"credentialId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"credentialId"}}}]}]}}]} as unknown as DocumentNode; export const GetUserTokensDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetUserTokens"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userTokens"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedKeyShare"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"expiresAt"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/frontend/apollo/schema.graphql b/frontend/apollo/schema.graphql index 4658c331..9691466a 100644 --- a/frontend/apollo/schema.graphql +++ b/frontend/apollo/schema.graphql @@ -35,6 +35,7 @@ type Query { githubRepos(credentialId: ID): [GitHubRepoType] gitlabProjects(credentialId: ID): [GitLabProjectType] gitlabGroups(credentialId: ID): [GitLabGroupType] + railwayProjects(credentialId: ID): [RailwayProjectType] testVaultCreds(credentialId: ID): Boolean testNomadCreds(credentialId: ID): Boolean } @@ -571,6 +572,24 @@ type GitLabGroupType { createdAt: DateTime } +type RailwayProjectType { + id: ID! + name: String! + environments: [RailwayEnvironmentType!]! + services: [RailwayServiceType!]! +} + +type RailwayEnvironmentType { + id: ID! + name: String! + projectId: ID! +} + +type RailwayServiceType { + id: ID! + name: String! +} + type Mutation { createOrganisation(id: ID!, identityKey: String!, name: String!, wrappedKeyring: String!, wrappedRecovery: String!): CreateOrganisationMutation inviteOrganisationMember(apps: [String], email: String!, orgId: ID!, role: String): InviteOrganisationMemberMutation @@ -602,6 +621,7 @@ type Mutation { createVaultSync(credentialId: ID, engine: String, envId: ID, path: String, vaultPath: String): CreateVaultSync createNomadSync(credentialId: ID, envId: ID, nomadNamespace: String, nomadPath: String, path: String): CreateNomadSync createGitlabCiSync(credentialId: ID, envId: ID, isGroup: Boolean, masked: Boolean, path: String, protected: Boolean, resourceId: String, resourcePath: String): CreateGitLabCISync + createRailwaySync(credentialId: ID, envId: ID, path: String, railwayEnvironment: RailwayResourceInput, railwayProject: RailwayResourceInput, railwayService: RailwayResourceInput): CreateRailwaySync createUserToken(expiry: BigInt, identityKey: String!, name: String!, orgId: ID!, token: String!, wrappedKeyShare: String!): CreateUserTokenMutation deleteUserToken(tokenId: ID!): DeleteUserTokenMutation createServiceToken(appId: ID!, environmentKeys: [EnvironmentKeyInput], expiry: BigInt, identityKey: String!, name: String!, token: String!, wrappedKeyShare: String!): CreateServiceTokenMutation @@ -755,6 +775,15 @@ type CreateGitLabCISync { sync: EnvironmentSyncType } +type CreateRailwaySync { + sync: EnvironmentSyncType +} + +input RailwayResourceInput { + id: ID! + name: String! +} + type CreateUserTokenMutation { ok: Boolean userToken: UserTokenType diff --git a/frontend/app/[team]/apps/[app]/syncing/page.tsx b/frontend/app/[team]/apps/[app]/syncing/page.tsx index 9a35be21..92b2c5b7 100644 --- a/frontend/app/[team]/apps/[app]/syncing/page.tsx +++ b/frontend/app/[team]/apps/[app]/syncing/page.tsx @@ -42,6 +42,12 @@ export default function Syncing({ params }: { params: { team: string; app: strin )} {data?.sseEnabled === true && ( <> + {activeUserIsAdmin && ( + + )} {data.syncs && data.syncs.length > 0 && (
Active Syncs
@@ -50,13 +56,6 @@ export default function Syncing({ params }: { params: { team: string; app: strin ))}
)} - - {activeUserIsAdmin && ( - - )} )} diff --git a/frontend/components/syncing/CreateProviderCredentials.tsx b/frontend/components/syncing/CreateProviderCredentials.tsx index 38219640..4834bc63 100644 --- a/frontend/components/syncing/CreateProviderCredentials.tsx +++ b/frontend/components/syncing/CreateProviderCredentials.tsx @@ -162,7 +162,7 @@ export const CreateProviderCredentials = (props: { )} {provider === null && ( -
+
{providers.map((provider) => ( + )} +
+ +
+ + + ) +} diff --git a/frontend/components/syncing/ServiceInfo.tsx b/frontend/components/syncing/ServiceInfo.tsx index e512585f..4c2649a6 100644 --- a/frontend/components/syncing/ServiceInfo.tsx +++ b/frontend/components/syncing/ServiceInfo.tsx @@ -1,4 +1,4 @@ -import { EnvironmentSyncType } from '@/apollo/graphql' +import { EnvironmentSyncType, RailwayProjectType, RailwayResourceInput } from '@/apollo/graphql' import { FaEyeSlash, FaLock } from 'react-icons/fa' export const ServiceInfo = (props: { sync: EnvironmentSyncType }) => { @@ -56,5 +56,15 @@ export const ServiceInfo = (props: { sync: EnvironmentSyncType }) => { {isProtected && } ) + } else if (sync.serviceInfo?.id?.includes('railway')) { + const project: RailwayResourceInput = JSON.parse(sync.options)['project'] + const environment: RailwayResourceInput = JSON.parse(sync.options)['environment'] + const service: RailwayResourceInput | undefined = JSON.parse(sync.options)['service'] + + return ( +
+ {project.name} {service ? ` - ${service.name}` : ''} ({environment.name}) +
+ ) } else return <>{sync.serviceInfo?.id} } diff --git a/frontend/graphql/mutations/syncing/railway/createRailwayEnvironmentSync.gql b/frontend/graphql/mutations/syncing/railway/createRailwayEnvironmentSync.gql new file mode 100644 index 00000000..c627fd3a --- /dev/null +++ b/frontend/graphql/mutations/syncing/railway/createRailwayEnvironmentSync.gql @@ -0,0 +1,33 @@ +mutation CreateNewRailwaySync( + $envId: ID! + $path: String! + $credentialId: ID! + $railwayProject: RailwayResourceInput! + $railwayEnvironment: RailwayResourceInput! + $railwayService: RailwayResourceInput +) { + createRailwaySync( + envId: $envId + path: $path + credentialId: $credentialId + railwayProject: $railwayProject + railwayEnvironment: $railwayEnvironment + railwayService: $railwayService + ) { + sync { + id + environment { + id + name + envType + } + serviceInfo { + id + name + } + isActive + lastSync + createdAt + } + } +} diff --git a/frontend/graphql/queries/syncing/railway/getProjects.gql b/frontend/graphql/queries/syncing/railway/getProjects.gql new file mode 100644 index 00000000..35b67543 --- /dev/null +++ b/frontend/graphql/queries/syncing/railway/getProjects.gql @@ -0,0 +1,14 @@ +query GetRailwayProjects($credentialId: ID!) { + railwayProjects(credentialId: $credentialId) { + id + name + environments { + id + name + } + services { + id + name + } + } +}