mirror of
https://github.com/coollabsio/coolify.git
synced 2026-09-28 02:06:37 -04:00
feat(v5): add application ingress routing
This commit is contained in:
@@ -335,6 +335,7 @@ function normalizeConnection(connection: V5ResourceConnection): CanvasConnection
|
||||
async function persistNewConnection(fromApplicationId: string, toApplicationId: string): Promise<void> {
|
||||
setNotice(null);
|
||||
|
||||
|
||||
try {
|
||||
const response = await fetch('/v5/resource-connections', {
|
||||
method: 'POST',
|
||||
@@ -378,6 +379,7 @@ function normalizeConnection(connection: V5ResourceConnection): CanvasConnection
|
||||
]),
|
||||
);
|
||||
|
||||
|
||||
try {
|
||||
const response = await fetch(`/v5/resource-connections/${connection.id}`, {
|
||||
method: 'PATCH',
|
||||
@@ -409,6 +411,7 @@ function normalizeConnection(connection: V5ResourceConnection): CanvasConnection
|
||||
}
|
||||
|
||||
async function deletePersistedConnection(connectionId: string): Promise<void> {
|
||||
|
||||
try {
|
||||
const response = await fetch(`/v5/resource-connections/${connectionId}`, {
|
||||
method: 'DELETE',
|
||||
@@ -615,6 +618,7 @@ function normalizeConnection(connection: V5ResourceConnection): CanvasConnection
|
||||
async function removeApplication(application: V5Application): Promise<void> {
|
||||
setNotice(null);
|
||||
|
||||
|
||||
try {
|
||||
const response = await fetch(`/v5/applications/${application.id}`, {
|
||||
method: 'DELETE',
|
||||
@@ -645,10 +649,73 @@ function normalizeConnection(connection: V5ResourceConnection): CanvasConnection
|
||||
}
|
||||
}
|
||||
|
||||
async function updateApplicationIngress(application: V5Application, enabled: boolean): Promise<void> {
|
||||
setNotice(null);
|
||||
|
||||
const domains = enabled
|
||||
? window
|
||||
.prompt('Domains for this app, separated by commas', application.domains.join(', '))
|
||||
?.split(',')
|
||||
.map((domain) => domain.trim())
|
||||
.filter(Boolean)
|
||||
: application.domains;
|
||||
|
||||
if (enabled && (!domains || domains.length === 0)) {
|
||||
setNotice('Add at least one domain before enabling app ingress.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const internalPort = enabled
|
||||
? Number(window.prompt('Internal container port', String(application.internalPort ?? '')))
|
||||
: application.internalPort;
|
||||
|
||||
if (enabled && (!Number.isInteger(internalPort) || Number(internalPort) < 1 || Number(internalPort) > 65535)) {
|
||||
setNotice('Choose a valid internal port before enabling app ingress.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedInternalPort = enabled ? Number(internalPort) : application.internalPort;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/v5/applications/${application.id}/ingress`, {
|
||||
method: 'PATCH',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': csrfToken(),
|
||||
},
|
||||
body: JSON.stringify({
|
||||
ingress_enabled: enabled,
|
||||
internal_port: selectedInternalPort,
|
||||
domains,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
setNotice('Could not update application ingress.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = (await response.json()) as { application: V5Application };
|
||||
setApplications((currentApplications) =>
|
||||
currentApplications.map((candidate) =>
|
||||
candidate.id === payload.application.id ? payload.application : candidate,
|
||||
),
|
||||
);
|
||||
} catch (error) {
|
||||
setNotice(error instanceof Error ? error.message : 'Could not update application ingress.');
|
||||
}
|
||||
}
|
||||
|
||||
async function addNginx(): Promise<void> {
|
||||
setIsCreating(true);
|
||||
setNotice(null);
|
||||
|
||||
|
||||
try {
|
||||
const response = await fetch('/v5/applications/nginx', {
|
||||
method: 'POST',
|
||||
@@ -697,6 +764,7 @@ function normalizeConnection(connection: V5ResourceConnection): CanvasConnection
|
||||
setIsRefreshing(true);
|
||||
setNotice(null);
|
||||
|
||||
|
||||
try {
|
||||
const response = await fetch('/v5/applications/refresh', {
|
||||
method: 'POST',
|
||||
@@ -1476,6 +1544,27 @@ function normalizeConnection(connection: V5ResourceConnection): CanvasConnection
|
||||
{application.containerName}
|
||||
</dd>
|
||||
</div>
|
||||
<div className="grid grid-cols-[auto_minmax(0,1fr)] items-center gap-3">
|
||||
<dt className="shrink-0 text-muted-foreground">Ingress</dt>
|
||||
<dd className="flex items-center justify-end gap-2 text-right">
|
||||
<span className="truncate text-muted-foreground">
|
||||
{application.ingressEnabled
|
||||
? `${application.domains.length} domain${application.domains.length === 1 ? '' : 's'} → ${application.internalPort ?? 'no port'}`
|
||||
: 'Private'}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onPointerDown={(event) => event.stopPropagation()}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
void updateApplicationIngress(application, !application.ingressEnabled);
|
||||
}}
|
||||
className="rounded-sm border border-border px-2 py-1 text-[0.625rem] font-semibold uppercase tracking-wide text-foreground transition hover:bg-muted"
|
||||
>
|
||||
{application.ingressEnabled ? 'Disable' : 'Enable'}
|
||||
</button>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -91,6 +91,9 @@ export type V5Application = {
|
||||
runtimeContainerId: string | null;
|
||||
serverName: string | null;
|
||||
meshNamespace: string;
|
||||
ingressEnabled: boolean;
|
||||
internalPort: number | null;
|
||||
domains: string[];
|
||||
meshFqdn: string;
|
||||
canvasX: number;
|
||||
canvasY: number;
|
||||
|
||||
Reference in New Issue
Block a user