Add support for service variables to Railway integration, add docs for Railway
@@ -249,7 +249,7 @@ export const getIntegrationAuthVercelBranches = async (req: Request, res: Respon
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of available Railway environments for Railway project with
|
||||
* Return list of Railway environments for Railway project with
|
||||
* id [appId]
|
||||
* @param req
|
||||
* @param res
|
||||
@@ -315,6 +315,84 @@ export const getIntegrationAuthRailwayEnvironments = async (req: Request, res: R
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of Railway services for Railway project with id
|
||||
* [appId]
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
export const getIntegrationAuthRailwayServices = async (req: Request, res: Response) => {
|
||||
const { integrationAuthId } = req.params;
|
||||
const appId = req.query.appId as string;
|
||||
|
||||
interface RailwayService {
|
||||
node: {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
}
|
||||
|
||||
interface Service {
|
||||
name: string;
|
||||
serviceId: string;
|
||||
}
|
||||
|
||||
let services: Service[] = [];
|
||||
|
||||
const query = `
|
||||
query project($id: String!) {
|
||||
project(id: $id) {
|
||||
createdAt
|
||||
deletedAt
|
||||
id
|
||||
description
|
||||
expiredAt
|
||||
isPublic
|
||||
isTempProject
|
||||
isUpdatable
|
||||
name
|
||||
prDeploys
|
||||
teamId
|
||||
updatedAt
|
||||
upstreamUrl
|
||||
services {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
if (appId && appId !== '') {
|
||||
const variables = {
|
||||
id: appId
|
||||
}
|
||||
|
||||
const { data: { data: { project: { services: { edges } } } } } = await request.post(INTEGRATION_RAILWAY_API_URL, {
|
||||
query,
|
||||
variables
|
||||
}, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${req.accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
services = edges.map((e: RailwayService) => ({
|
||||
name: e.node.name,
|
||||
serviceId: e.node.id
|
||||
}));
|
||||
}
|
||||
|
||||
return res.status(200).send({
|
||||
services
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete integration authorization with id [integrationAuthId]
|
||||
* @param req
|
||||
|
||||
@@ -25,6 +25,8 @@ export const createIntegration = async (req: Request, res: Response) => {
|
||||
sourceEnvironment,
|
||||
targetEnvironment,
|
||||
targetEnvironmentId,
|
||||
targetService,
|
||||
targetServiceId,
|
||||
owner,
|
||||
path,
|
||||
region
|
||||
@@ -41,6 +43,8 @@ export const createIntegration = async (req: Request, res: Response) => {
|
||||
appId,
|
||||
targetEnvironment,
|
||||
targetEnvironmentId,
|
||||
targetService,
|
||||
targetServiceId,
|
||||
owner,
|
||||
path,
|
||||
region,
|
||||
|
||||
@@ -355,10 +355,7 @@ const getAppsRailway = async ({ accessToken }: { accessToken: string }) => {
|
||||
}
|
||||
`;
|
||||
|
||||
const variables = {
|
||||
// userId: '<USER_ID_GOES_HERE>', // Replace with the desired user ID or remove if not needed
|
||||
// teamId: '<TEAM_ID_GOES_HERE>', // Replace with the desired team ID or remove if not needed
|
||||
};
|
||||
const variables = {};
|
||||
|
||||
const { data: { data: { projects: { edges }}} } = await request.post(INTEGRATION_RAILWAY_API_URL, {
|
||||
query,
|
||||
@@ -367,6 +364,7 @@ const getAppsRailway = async ({ accessToken }: { accessToken: string }) => {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
'Accept-Encoding': 'application/json'
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1179,6 +1179,7 @@ const syncSecretsRailway = async ({
|
||||
accessToken: string;
|
||||
}) => {
|
||||
try {
|
||||
|
||||
const query = `
|
||||
mutation UpsertVariables($input: VariableCollectionUpsertInput!) {
|
||||
variableCollectionUpsert(input: $input)
|
||||
@@ -1188,6 +1189,7 @@ const syncSecretsRailway = async ({
|
||||
const input = {
|
||||
projectId: integration.appId,
|
||||
environmentId: integration.targetEnvironmentId,
|
||||
...(integration.targetServiceId ? { serviceId: integration.targetServiceId } : {}),
|
||||
replace: true,
|
||||
variables: secrets
|
||||
};
|
||||
@@ -1201,6 +1203,7 @@ const syncSecretsRailway = async ({
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
'Accept-Encoding': 'application/json'
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -21,10 +21,12 @@ export interface IIntegration {
|
||||
environment: string;
|
||||
isActive: boolean;
|
||||
app: string;
|
||||
appId: string;
|
||||
owner: string;
|
||||
targetEnvironment: string;
|
||||
targetEnvironmentId: string;
|
||||
appId: string;
|
||||
targetService: string;
|
||||
targetServiceId: string;
|
||||
path: string;
|
||||
region: string;
|
||||
integration:
|
||||
@@ -78,6 +80,16 @@ const integrationSchema = new Schema<IIntegration>(
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
targetService: {
|
||||
// railway-specific service
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
targetServiceId: {
|
||||
// railway-specific service
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
owner: {
|
||||
// github-specific repo owner-login
|
||||
type: String,
|
||||
|
||||
@@ -31,6 +31,8 @@ router.post( // new: add new integration for integration auth
|
||||
body('sourceEnvironment').trim(),
|
||||
body('targetEnvironment').trim(),
|
||||
body('targetEnvironmentId').trim(),
|
||||
body('targetService').trim(),
|
||||
body('targetServiceId').trim(),
|
||||
body('owner').trim(),
|
||||
body('path').trim(),
|
||||
body('region').trim(),
|
||||
|
||||
@@ -125,6 +125,20 @@ router.get(
|
||||
integrationAuthController.getIntegrationAuthRailwayEnvironments
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/:integrationAuthId/railway/services',
|
||||
requireAuth({
|
||||
acceptedAuthModes: ['jwt']
|
||||
}),
|
||||
requireIntegrationAuthorizationAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER]
|
||||
}),
|
||||
param('integrationAuthId').exists().isString(),
|
||||
query('appId').exists().isString(),
|
||||
validateRequest,
|
||||
integrationAuthController.getIntegrationAuthRailwayServices
|
||||
);
|
||||
|
||||
router.delete(
|
||||
'/:integrationAuthId',
|
||||
requireAuth({
|
||||
|
||||
BIN
docs/images/integrations-railway-authorization.png
Normal file
|
After Width: | Height: | Size: 499 KiB |
BIN
docs/images/integrations-railway-create.png
Normal file
|
After Width: | Height: | Size: 587 KiB |
BIN
docs/images/integrations-railway-dashboard.png
Normal file
|
After Width: | Height: | Size: 496 KiB |
BIN
docs/images/integrations-railway-token.png
Normal file
|
After Width: | Height: | Size: 570 KiB |
BIN
docs/images/integrations-railway.png
Normal file
|
After Width: | Height: | Size: 391 KiB |
|
Before Width: | Height: | Size: 424 KiB After Width: | Height: | Size: 1.1 MiB |
54
docs/integrations/cloud/railway.mdx
Normal file
@@ -0,0 +1,54 @@
|
||||
---
|
||||
title: "Railway"
|
||||
description: "How to automatically sync secrets from Infisical into your Railway projects and services"
|
||||
---
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- Set up and add envars to [Infisical Cloud](https://app.infisical.com)
|
||||
|
||||
|
||||
## Navigate to your project's integrations tab
|
||||
|
||||

|
||||
|
||||
## Enter your Railway API Token
|
||||
|
||||
Obtain a Railway API Token in your Railway [Account Settings > Tokens](https://railway.app/account/tokens).
|
||||
|
||||

|
||||

|
||||
|
||||
<Note>
|
||||
If this is your first time creating a Railway API token, then you'll be prompted to join
|
||||
Railway's Private Boarding Beta program on the Railway Account Settings > Tokens page.
|
||||
|
||||
Note that Railway project tokens will not work for this integration since they don't work with
|
||||
Railway's Public API.
|
||||
</Note>
|
||||
|
||||
Press on the Railway tile and input your Railway API Key to grant Infisical access to your Railway account.
|
||||
|
||||

|
||||
|
||||
<Info>
|
||||
If this is your project's first cloud integration, then you'll have to grant
|
||||
Infisical access to your project's environment variables. Although this step
|
||||
breaks E2EE, it's necessary for Infisical to sync the environment variables to
|
||||
the cloud platform.
|
||||
</Info>
|
||||
|
||||
## Start integration
|
||||
|
||||
Select which Infisical environment secrets you want to sync to which Railway project and environment (and optionally service). Lastly, press create integration to start syncing secrets to Railway.
|
||||
|
||||

|
||||
|
||||
<Note>
|
||||
Infisical integrates with both Railway's [shared variables](https://blog.railway.app/p/shared-variables-release) at the project environment level as well as service variables at the service level.
|
||||
|
||||
To sync secrets to a specific service in a project, you can select a service from the Railway Service dropdown; otherwise, leaving it empty will sync secrets to the shared variables of that project.
|
||||
</Note>
|
||||
|
||||

|
||||
|
||||
@@ -18,6 +18,7 @@ Missing an integration? Throw in a [request](https://github.com/Infisical/infisi
|
||||
| [Vercel](/integrations/cloud/vercel) | Cloud | Available |
|
||||
| [Netlify](/integrations/cloud/netlify) | Cloud | Available |
|
||||
| [Render](/integrations/cloud/render) | Cloud | Available |
|
||||
| [Railway](/integrations/cloud/railway) | Cloud | Available |
|
||||
| [Fly.io](/integrations/cloud/flyio) | Cloud | Available |
|
||||
| [AWS Parameter Store](/integrations/cloud/aws-parameter-store) | Cloud | Available |
|
||||
| [AWS Secret Manager](/integrations/cloud/aws-secret-manager) | Cloud | Available |
|
||||
|
||||
@@ -149,6 +149,7 @@
|
||||
"integrations/cloud/vercel",
|
||||
"integrations/cloud/netlify",
|
||||
"integrations/cloud/render",
|
||||
"integrations/cloud/railway",
|
||||
"integrations/cloud/flyio",
|
||||
"integrations/cloud/azure-key-vault",
|
||||
"integrations/cicd/githubactions",
|
||||
|
||||
@@ -12,6 +12,7 @@ const integrationSlugNameMapping: Mapping = {
|
||||
'github': 'GitHub',
|
||||
'gitlab': 'GitLab',
|
||||
'render': 'Render',
|
||||
'railway': 'Railway',
|
||||
'flyio': 'Fly.io',
|
||||
'circleci': 'CircleCI',
|
||||
'travisci': 'TravisCI'
|
||||
|
||||
@@ -45,6 +45,7 @@ type Props = {
|
||||
handleDeleteIntegration: (args: { integration: Integration }) => void;
|
||||
};
|
||||
|
||||
// TODO: refactor
|
||||
const IntegrationTile = ({
|
||||
integration,
|
||||
integrations,
|
||||
@@ -55,7 +56,6 @@ const IntegrationTile = ({
|
||||
handleDeleteIntegration
|
||||
}: Props) => {
|
||||
|
||||
// set initial environment. This find will only execute when component is mounting
|
||||
const [integrationEnvironment, setIntegrationEnvironment] = useState<Props['environments'][0]>(
|
||||
environments.find(({ slug }) => slug === integration?.environment) || {
|
||||
name: '',
|
||||
@@ -176,6 +176,21 @@ const IntegrationTile = ({
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
case 'railway':
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-2 text-xs font-semibold text-gray-400">ENVIRONMENT</div>
|
||||
<ListBox
|
||||
data={
|
||||
!integration.isActive
|
||||
? ['Production', 'Deploy previews', 'Branch deploys', 'Local development']
|
||||
: null
|
||||
}
|
||||
isSelected={integration.targetEnvironment}
|
||||
onChange={setIntegrationTargetEnvironment}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
default:
|
||||
return <div />;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export {
|
||||
useGetIntegrationAuthApps,
|
||||
useGetIntegrationAuthById,
|
||||
useGetIntegrationAuthRailwayEnvironments,
|
||||
useGetIntegrationAuthRailwayServices,
|
||||
useGetIntegrationAuthTeams,
|
||||
useGetIntegrationAuthVercelBranches,
|
||||
useGetRailwayEnvironments
|
||||
} from './queries';
|
||||
useGetIntegrationAuthVercelBranches} from './queries';
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
App,
|
||||
Environment,
|
||||
IntegrationAuth,
|
||||
Service,
|
||||
Team
|
||||
} from './types';
|
||||
|
||||
@@ -27,6 +28,13 @@ const integrationAuthKeys = {
|
||||
integrationAuthId: string;
|
||||
appId: string;
|
||||
}) => [{ integrationAuthId, appId }, 'integrationAuthRailwayEnvironments'] as const,
|
||||
getIntegrationAuthRailwayServices: ({
|
||||
integrationAuthId,
|
||||
appId
|
||||
}: {
|
||||
integrationAuthId: string;
|
||||
appId: string;
|
||||
}) => [{ integrationAuthId, appId }, 'integrationAuthRailwayServices'] as const
|
||||
}
|
||||
|
||||
const fetchIntegrationAuthById = async (integrationAuthId: string) => {
|
||||
@@ -86,6 +94,22 @@ const fetchIntegrationAuthRailwayEnvironments = async ({
|
||||
return environments;
|
||||
}
|
||||
|
||||
const fetchIntegrationAuthRailwayServices = async ({
|
||||
integrationAuthId,
|
||||
appId
|
||||
}: {
|
||||
integrationAuthId: string;
|
||||
appId: string;
|
||||
}) => {
|
||||
const { data: { services } } = await apiRequest.get<{ services: Service[] }>(`/api/v1/integration-auth/${integrationAuthId}/railway/services`, {
|
||||
params: {
|
||||
appId
|
||||
}
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
export const useGetIntegrationAuthById = (integrationAuthId: string) => {
|
||||
return useQuery({
|
||||
queryKey: integrationAuthKeys.getIntegrationAuthById(integrationAuthId),
|
||||
@@ -139,7 +163,7 @@ export const useGetIntegrationAuthVercelBranches = ({
|
||||
});
|
||||
}
|
||||
|
||||
export const useGetRailwayEnvironments = ({
|
||||
export const useGetIntegrationAuthRailwayEnvironments = ({
|
||||
integrationAuthId,
|
||||
appId
|
||||
}: {
|
||||
@@ -158,3 +182,23 @@ export const useGetRailwayEnvironments = ({
|
||||
enabled: true
|
||||
});
|
||||
}
|
||||
|
||||
export const useGetIntegrationAuthRailwayServices = ({
|
||||
integrationAuthId,
|
||||
appId
|
||||
}: {
|
||||
integrationAuthId: string;
|
||||
appId: string;
|
||||
}) => {
|
||||
return useQuery({
|
||||
queryKey: integrationAuthKeys.getIntegrationAuthRailwayServices({
|
||||
integrationAuthId,
|
||||
appId,
|
||||
}),
|
||||
queryFn: () => fetchIntegrationAuthRailwayServices({
|
||||
integrationAuthId,
|
||||
appId,
|
||||
}),
|
||||
enabled: true
|
||||
});
|
||||
}
|
||||
@@ -21,3 +21,8 @@ export type Environment = {
|
||||
name: string;
|
||||
environmentId: string;
|
||||
}
|
||||
|
||||
export type Service = {
|
||||
name: string;
|
||||
serviceId: string;
|
||||
}
|
||||
@@ -8,6 +8,8 @@ interface Props {
|
||||
sourceEnvironment: string;
|
||||
targetEnvironment: string | null;
|
||||
targetEnvironmentId: string | null;
|
||||
targetService: string | null;
|
||||
targetServiceId: string | null;
|
||||
owner: string | null;
|
||||
path: string | null;
|
||||
region: string | null;
|
||||
@@ -26,6 +28,8 @@ const createIntegration = ({
|
||||
sourceEnvironment,
|
||||
targetEnvironment,
|
||||
targetEnvironmentId,
|
||||
targetService,
|
||||
targetServiceId,
|
||||
owner,
|
||||
path,
|
||||
region
|
||||
@@ -43,6 +47,8 @@ const createIntegration = ({
|
||||
sourceEnvironment,
|
||||
targetEnvironment,
|
||||
targetEnvironmentId,
|
||||
targetService,
|
||||
targetServiceId,
|
||||
owner,
|
||||
path,
|
||||
region
|
||||
|
||||
@@ -99,6 +99,8 @@ export default function AWSParameterStoreCreateIntegrationPage() {
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path,
|
||||
region: selectedAWSRegion
|
||||
|
||||
@@ -98,6 +98,8 @@ export default function AWSSecretManagerCreateIntegrationPage() {
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: selectedAWSRegion
|
||||
|
||||
@@ -63,6 +63,8 @@ export default function AzureKeyVaultCreateIntegrationPage() {
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
|
||||
@@ -61,6 +61,8 @@ export default function CircleCICreateIntegrationPage() {
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null,
|
||||
|
||||
@@ -62,6 +62,8 @@ export default function FlyioCreateIntegrationPage() {
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
|
||||
@@ -65,6 +65,8 @@ export default function GitHubCreateIntegrationPage() {
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: targetApp.owner,
|
||||
path: null,
|
||||
region: null
|
||||
|
||||
@@ -90,6 +90,8 @@ export default function GitLabCreateIntegrationPage() {
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
|
||||
@@ -61,6 +61,8 @@ export default function HerokuCreateIntegrationPage() {
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
|
||||
@@ -70,6 +70,8 @@ export default function NetlifyCreateIntegrationPage() {
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
|
||||
@@ -14,7 +14,8 @@ import {
|
||||
import {
|
||||
useGetIntegrationAuthApps,
|
||||
useGetIntegrationAuthById,
|
||||
useGetRailwayEnvironments
|
||||
useGetIntegrationAuthRailwayEnvironments,
|
||||
useGetIntegrationAuthRailwayServices
|
||||
} from '../../../hooks/api/integrationAuth';
|
||||
import { useGetWorkspaceById } from '../../../hooks/api/workspace';
|
||||
import createIntegration from "../../api/integrations/createIntegration";
|
||||
@@ -24,6 +25,8 @@ export default function RailwayCreateIntegrationPage() {
|
||||
|
||||
const [targetAppId, setTargetAppId] = useState('');
|
||||
const [targetEnvironmentId, setTargetEnvironmentId] = useState('');
|
||||
const [targetServiceId, setTargetServiceId] = useState('');
|
||||
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
@@ -33,8 +36,11 @@ export default function RailwayCreateIntegrationPage() {
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: integrationAuthId as string ?? ''
|
||||
});
|
||||
|
||||
const { data: targetEnvironments } = useGetRailwayEnvironments({
|
||||
const { data: targetEnvironments } = useGetIntegrationAuthRailwayEnvironments({
|
||||
integrationAuthId: integrationAuthId as string ?? '',
|
||||
appId: targetAppId
|
||||
});
|
||||
const { data: targetServices } = useGetIntegrationAuthRailwayServices({
|
||||
integrationAuthId: integrationAuthId as string ?? '',
|
||||
appId: targetAppId
|
||||
});
|
||||
@@ -65,6 +71,12 @@ export default function RailwayCreateIntegrationPage() {
|
||||
}
|
||||
}, [targetEnvironments]);
|
||||
|
||||
const filteredServices = targetServices
|
||||
?.concat({
|
||||
name: '',
|
||||
serviceId: ''
|
||||
});
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
@@ -76,6 +88,8 @@ export default function RailwayCreateIntegrationPage() {
|
||||
|
||||
if (!targetApp || !targetApp.appId || !targetEnvironment) return;
|
||||
|
||||
const targetService = targetServices?.find((service) => service.serviceId === targetServiceId);
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
@@ -84,6 +98,8 @@ export default function RailwayCreateIntegrationPage() {
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: targetEnvironment.name,
|
||||
targetEnvironmentId: targetEnvironment.environmentId,
|
||||
targetService: targetService ? targetService.name : null,
|
||||
targetServiceId: targetService ? targetService.serviceId : null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
@@ -99,7 +115,7 @@ export default function RailwayCreateIntegrationPage() {
|
||||
}
|
||||
}
|
||||
|
||||
return workspace && selectedSourceEnvironment && integrationAuthApps && targetEnvironments ? (
|
||||
return workspace && selectedSourceEnvironment && integrationAuthApps && targetEnvironments && filteredServices ? (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className="text-center">Railway Integration</CardTitle>
|
||||
@@ -158,6 +174,19 @@ export default function RailwayCreateIntegrationPage() {
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl label="Railway Service (Optional)">
|
||||
<Select
|
||||
value={targetServiceId}
|
||||
onValueChange={(val) => setTargetServiceId(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
>
|
||||
{filteredServices.map((targetService) => (
|
||||
<SelectItem value={targetService.serviceId as string} key={`target-service-${targetService.serviceId as string}`}>
|
||||
{targetService.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
|
||||
@@ -61,6 +61,8 @@ export default function RenderCreateIntegrationPage() {
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
|
||||
@@ -61,6 +61,8 @@ export default function TravisCICreateIntegrationPage() {
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null,
|
||||
|
||||
@@ -88,6 +88,8 @@ export default function VercelCreateIntegrationPage() {
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path,
|
||||
region: null
|
||||
|
||||