Permanently remove the service and all associated data.
This action cannot be undone.
-
What's deleted:
+
What's deleted:
- All service data
- Qovery configuration
diff --git a/libs/domains/services/feature/src/lib/service-links-popover/service-links-popover.tsx b/libs/domains/services/feature/src/lib/service-links-popover/service-links-popover.tsx
index abf254cebe4..1ce3d2b7ffc 100644
--- a/libs/domains/services/feature/src/lib/service-links-popover/service-links-popover.tsx
+++ b/libs/domains/services/feature/src/lib/service-links-popover/service-links-popover.tsx
@@ -65,16 +65,16 @@ export function ServiceLinksPopover({
{children}
-
+
{filteredLinks?.length ?? 0} {pluralize(filteredLinks?.length ?? 0, 'link')} attached
{serviceType !== 'HELM' && (
-
+
Customize
@@ -84,12 +84,9 @@ export function ServiceLinksPopover({
{nginxLinks.map((link: LinkProps) => (
-
-
+
- {link.internal_port}
+ {link.internal_port}
))}
{nginxLinks.length > 0 && gatewayApiLinks.length > 0 && (
<>
-
- -
+
+ -
Gateway API / Envoy stack
more info
@@ -125,11 +122,7 @@ export function ServiceLinksPopover({
classNameContent="max-w-xs"
>
-
+
@@ -137,12 +130,9 @@ export function ServiceLinksPopover({
)}
{gatewayApiLinks.map((link: LinkProps) => (
-
-
+
-
{link.internal_port}
+
{link.internal_port}
))}
diff --git a/libs/domains/services/feature/src/lib/service-list/service-list-cells/index.ts b/libs/domains/services/feature/src/lib/service-list/service-list-cells/index.ts
new file mode 100644
index 00000000000..f0cbe4b47a6
--- /dev/null
+++ b/libs/domains/services/feature/src/lib/service-list/service-list-cells/index.ts
@@ -0,0 +1,4 @@
+export * from './service-name-cell'
+export * from './service-version-cell'
+export * from './service-last-deployment-cell'
+export * from './service-running-status-cell'
diff --git a/libs/domains/services/feature/src/lib/service-list/service-list-cells/service-last-deployment-cell.tsx b/libs/domains/services/feature/src/lib/service-list/service-list-cells/service-last-deployment-cell.tsx
new file mode 100644
index 00000000000..c7ad4e7fa1a
--- /dev/null
+++ b/libs/domains/services/feature/src/lib/service-list/service-list-cells/service-last-deployment-cell.tsx
@@ -0,0 +1,38 @@
+import { type AnyService } from '@qovery/domains/services/data-access'
+import { DEPLOYMENT_LOGS_VERSION_URL, ENVIRONMENT_LOGS_URL } from '@qovery/shared/routes'
+import { Icon, Link, Tooltip } from '@qovery/shared/ui'
+import { dateUTCString, timeAgo } from '@qovery/shared/util-dates'
+
+type ServiceLastDeploymentCellProps = {
+ service: AnyService
+ organizationId: string
+ projectId: string
+ environmentId: string
+}
+
+export function ServiceLastDeploymentCell({
+ service,
+ organizationId,
+ projectId,
+ environmentId,
+}: ServiceLastDeploymentCellProps) {
+ const value = 'deploymentStatus' in service ? service.deploymentStatus.last_deployment_date : undefined
+ const linkLog =
+ ENVIRONMENT_LOGS_URL(organizationId, projectId, environmentId) +
+ DEPLOYMENT_LOGS_VERSION_URL(service?.id, service?.deploymentStatus?.execution_id)
+
+ return value ? (
+
event.stopPropagation()}
+ >
+
+ {timeAgo(new Date(value))}
+
+
+
+ ) : (
+
-
+ )
+}
diff --git a/libs/domains/services/feature/src/lib/service-list/service-list-cells/service-name-cell.tsx b/libs/domains/services/feature/src/lib/service-list/service-list-cells/service-name-cell.tsx
new file mode 100644
index 00000000000..8f071e24522
--- /dev/null
+++ b/libs/domains/services/feature/src/lib/service-list/service-list-cells/service-name-cell.tsx
@@ -0,0 +1,248 @@
+import { useNavigate } from '@tanstack/react-router'
+import { type Environment, ServiceTypeEnum, type Status } from 'qovery-typescript-axios'
+import { match } from 'ts-pattern'
+import { type AnyService } from '@qovery/domains/services/data-access'
+import {
+ APPLICATION_GENERAL_URL,
+ APPLICATION_URL,
+ DATABASE_GENERAL_URL,
+ DATABASE_URL,
+ DEPLOYMENT_LOGS_VERSION_URL,
+ ENVIRONMENT_LOGS_URL,
+ SERVICES_GENERAL_URL,
+} from '@qovery/shared/routes'
+import { AnimatedGradientText, Badge, Button, Icon, Link, Tooltip } from '@qovery/shared/ui'
+import { formatCronExpression, pluralize, upperCaseFirstLetter } from '@qovery/shared/util-js'
+import ServiceActionToolbar from '../../service-action-toolbar/service-action-toolbar'
+import { ServiceAvatar } from '../../service-avatar/service-avatar'
+import ServiceLinksPopover from '../../service-links-popover/service-links-popover'
+import ServiceTemplateIndicator from '../../service-template-indicator/service-template-indicator'
+
+export function ServiceNameCell({
+ service,
+ environment,
+ deploymentStatus,
+}: {
+ service: AnyService
+ environment: Environment
+ deploymentStatus?: Status
+}) {
+ const navigate = useNavigate()
+
+ const deploymentRequestsCount = Number(deploymentStatus?.deployment_requests_count)
+
+ const serviceLink = match(service)
+ .with(
+ { serviceType: ServiceTypeEnum.DATABASE },
+ ({ id }) =>
+ DATABASE_URL(environment.organization.id, environment.project.id, service.environment.id, id) +
+ DATABASE_GENERAL_URL
+ )
+ .otherwise(
+ ({ id }) =>
+ APPLICATION_URL(environment.organization.id, environment.project.id, service.environment.id, id) +
+ SERVICES_GENERAL_URL
+ )
+
+ const LinkDeploymentStatus = () => {
+ const environmentLog = ENVIRONMENT_LOGS_URL(environment.organization.id, environment.project.id, environment.id)
+ const deploymentLog = DEPLOYMENT_LOGS_VERSION_URL(service.id, deploymentStatus?.execution_id)
+ // const precheckLog = ENVIRONMENT_PRE_CHECK_LOGS_URL(deploymentStatus?.execution_id ?? '')
+
+ return match(deploymentStatus?.state)
+ .with('DEPLOYMENT_QUEUED', 'DELETE_QUEUED', 'STOP_QUEUED', 'RESTART_QUEUED', (s) => (
+
{upperCaseFirstLetter(s).replace('_', ' ')}...
+ ))
+ .with('CANCELED', () =>
Last deployment aborted)
+ .with('DEPLOYING', 'RESTARTING', 'BUILDING', 'DELETING', 'CANCELING', 'STOPPING', (s) => (
+
e.stopPropagation()}
+ >
+
+
+ {upperCaseFirstLetter(s)}...
+
+
+
+ ))
+ .with('DEPLOYMENT_ERROR', 'DELETE_ERROR', 'STOP_ERROR', 'RESTART_ERROR', 'BUILD_ERROR', () => (
+
e.stopPropagation()}
+ >
+ Last deployment failed
+
+
+ ))
+ .otherwise(() => null)
+ }
+
+ return (
+
+
+
+
+
+ {match(service)
+ .with({ serviceType: 'DATABASE' }, (db) => {
+ return (
+
+
+
+ e.stopPropagation()}
+ >
+ {db.name}
+
+
+
+
+
+ )
+ })
+ .with({ serviceType: 'JOB' }, (job) => {
+ const schedule = match(job)
+ .with(
+ { job_type: 'CRON' },
+ ({ schedule }) =>
+ `Triggered: ${formatCronExpression(schedule.cronjob?.scheduled_at)} (${schedule.cronjob?.timezone})`
+ )
+ .with({ job_type: 'LIFECYCLE' }, ({ schedule }) => {
+ const actions = [
+ schedule.on_start && 'Deploy',
+ schedule.on_stop && 'Stop',
+ schedule.on_delete && 'Delete',
+ ]
+ .filter(Boolean)
+ .join(' - ')
+ return actions ? `Triggered on: ${actions}` : undefined
+ })
+ .exhaustive()
+
+ return (
+
+
+
+ e.stopPropagation()}
+ >
+ {service.name}
+
+
+
+
+
+
+
+
+
+
+ )
+ })
+ .otherwise(() => (
+
+
+ e.stopPropagation()}
+ >
+ {service.name}
+
+
+
+
+ ))}
+
+ {deploymentRequestsCount > 0 && (
+
+
+
+ {deploymentRequestsCount}
+
+
+ )}
+
+
+
+ {'auto_deploy' in service && service.auto_deploy && (
+
+
+
+
+
+ )}
+
e.stopPropagation()}>
+
+
+
+
+
+
e.stopPropagation()}>
+ undefined)
+ .with(
+ { serviceType: 'DATABASE', mode: 'CONTAINER' },
+ () => () =>
+ navigate({
+ to:
+ DATABASE_URL(environment.organization.id, environment.project.id, environment.id, service.id) +
+ DATABASE_GENERAL_URL,
+ state: {
+ hasShell: true,
+ } as any,
+ })
+ )
+ .otherwise(
+ () => () =>
+ navigate({
+ to:
+ APPLICATION_URL(environment.organization.id, environment.project.id, environment.id, service.id) +
+ APPLICATION_GENERAL_URL,
+ state: {
+ hasShell: true,
+ } as any,
+ })
+ )}
+ />
+
+
+
+ )
+}
diff --git a/libs/domains/services/feature/src/lib/service-list/service-list-cells/service-running-status-cell.tsx b/libs/domains/services/feature/src/lib/service-list/service-list-cells/service-running-status-cell.tsx
new file mode 100644
index 00000000000..2b3e5d2826e
--- /dev/null
+++ b/libs/domains/services/feature/src/lib/service-list/service-list-cells/service-running-status-cell.tsx
@@ -0,0 +1,109 @@
+import { ServiceTypeEnum } from 'qovery-typescript-axios'
+import { ServiceSubActionDto } from 'qovery-ws-typescript-axios'
+import { match } from 'ts-pattern'
+import { type AnyService } from '@qovery/domains/services/data-access'
+import {
+ APPLICATION_URL,
+ CLUSTER_URL,
+ DATABASE_GENERAL_URL,
+ DATABASE_URL,
+ SERVICES_GENERAL_URL,
+} from '@qovery/shared/routes'
+import { Link, Skeleton, StatusChip, Tooltip } from '@qovery/shared/ui'
+import useCheckRunningStatusClosed from '../../hooks/use-check-running-status-closed/use-check-running-status-closed'
+
+type ServiceRunningStatusCellProps = {
+ service: AnyService
+ organizationId: string
+ projectId: string
+ environment: Environment
+ clusterId: string
+}
+
+export function ServiceRunningStatusCell({
+ service,
+ organizationId,
+ projectId,
+ environment,
+ clusterId,
+}: ServiceRunningStatusCellProps) {
+ const stateLabel = service.runningStatus.stateLabel
+
+ const { data: checkRunningStatusClosed } = useCheckRunningStatusClosed({
+ clusterId,
+ environmentId: environment.id,
+ })
+
+ const Wrapper = ({ children }: { children: React.ReactNode }) =>
{children}
+
+ const link = match(service)
+ .with(
+ { serviceType: ServiceTypeEnum.DATABASE },
+ ({ id }) => DATABASE_URL(organizationId, projectId, environment.id, id) + DATABASE_GENERAL_URL
+ )
+ .otherwise(({ id }) => APPLICATION_URL(organizationId, projectId, environment.id, id) + SERVICES_GENERAL_URL)
+
+ const value = match(service.runningStatus.triggered_action)
+ .with({ sub_action: ServiceSubActionDto.TERRAFORM_PLAN_ONLY }, () => 'Plan ' + stateLabel.toLowerCase())
+ .with({ sub_action: ServiceSubActionDto.TERRAFORM_PLAN_AND_APPLY }, () => 'Apply ' + stateLabel.toLowerCase())
+ .with(
+ { sub_action: ServiceSubActionDto.TERRAFORM_MIGRATE_STATE },
+ () => 'Migrate state ' + stateLabel.toLowerCase()
+ )
+ .with(
+ { sub_action: ServiceSubActionDto.TERRAFORM_FORCE_UNLOCK_STATE },
+ () => 'Force unlock ' + stateLabel.toLowerCase()
+ )
+ .with({ sub_action: ServiceSubActionDto.TERRAFORM_DESTROY }, () => 'Destroy ' + stateLabel.toLocaleString())
+ .with({ sub_action: ServiceSubActionDto.NONE }, () => stateLabel)
+ .with(undefined, () => stateLabel)
+ .exhaustive()
+
+ if (checkRunningStatusClosed) {
+ return (
+
+
+ e.stopPropagation()}
+ className="gap-2 whitespace-nowrap text-sm"
+ size="md"
+ color="neutral"
+ variant="outline"
+ radius="full"
+ >
+
+ Status unavailable
+
+
+
+ )
+ }
+
+ return (
+
+
+
+ e.stopPropagation()}
+ className="gap-2 whitespace-nowrap text-sm"
+ size="md"
+ color="neutral"
+ variant="outline"
+ radius="full"
+ >
+ s.deploymentStatus?.state)
+ .otherwise((s) => s.runningStatus?.state)}
+ />
+ {value}
+
+
+
+
+ )
+}
diff --git a/libs/domains/services/feature/src/lib/service-list/service-list-cells/service-version-cell.tsx b/libs/domains/services/feature/src/lib/service-list/service-list-cells/service-version-cell.tsx
new file mode 100644
index 00000000000..8ba9a9defc2
--- /dev/null
+++ b/libs/domains/services/feature/src/lib/service-list/service-list-cells/service-version-cell.tsx
@@ -0,0 +1,220 @@
+import {
+ type ApplicationGitRepository,
+ type ContainerResponse,
+ type HelmSourceRepositoryResponse,
+} from 'qovery-typescript-axios'
+import { P, match } from 'ts-pattern'
+import {
+ type AnyService,
+ type Application,
+ type Database,
+ type Helm,
+ type Job,
+ type Terraform,
+} from '@qovery/domains/services/data-access'
+import {
+ IconEnum,
+ isHelmGitSource,
+ isHelmRepositorySource,
+ isJobContainerSource,
+ isJobGitSource,
+} from '@qovery/shared/enums'
+import { ExternalLink, Icon, Tooltip, Truncate } from '@qovery/shared/ui'
+import { buildGitProviderUrl } from '@qovery/shared/util-git'
+import { containerRegistryKindToIcon } from '@qovery/shared/util-js'
+import LastCommit from '../../last-commit/last-commit'
+import LastVersion from '../../last-version/last-version'
+
+type ServiceVersionCellProps = {
+ service: AnyService
+ organizationId: string
+ projectId: string
+}
+
+export function ServiceVersionCell({ service, organizationId, projectId }: ServiceVersionCellProps) {
+ const gitInfo = (service: Application | Job | Helm | Terraform, gitRepository?: ApplicationGitRepository) =>
+ gitRepository && (
+
e.stopPropagation()}>
+
+
+
+
+
+
+
+ {gitRepository.branch && gitRepository.url && (
+
+
+
+
+
+
+ )}
+
+
+
+ )
+ const containerInfo = (containerImage?: Pick
) =>
+ containerImage && (
+ e.stopPropagation()}>
+
+
+
+
+ {containerImage.registry.name.length >= 20 && (
+ <>
+ {containerImage.registry.name}
+ >
+ )}{' '}
+ {containerImage.registry.url}
+
+ }
+ >
+
+ {containerImage.registry.name.length >= 20 ? (
+
+ ) : (
+ containerImage.registry.name.toLowerCase()
+ )}
+
+
+
+
+
+
+
+
+ {(service.serviceType === 'CONTAINER' ||
+ (service.serviceType === 'JOB' && isJobContainerSource(service.source))) && (
+
+ )}
+
+ )
+
+ const datasourceInfo = (datasource?: Pick) =>
+ datasource && (
+
+
+
+ {datasource.type.toLowerCase().replace('sql', 'SQL').replace('db', 'DB')}
+
+
+ v
+ {datasource.version}
+
+
+ )
+
+ const helmInfo = (helmRepository?: HelmSourceRepositoryResponse) =>
+ helmRepository && (
+
+
e.stopPropagation()}>
+
+
+
+ {helmRepository.repository?.name.length > 20 && (
+ <>
+ {helmRepository.repository?.name}
+ >
+ )}
+ {helmRepository.repository?.url}
+
+ }
+ >
+
+ {helmRepository.repository?.name.length > 20 ? (
+
+ ) : (
+ helmRepository.repository?.name.toLowerCase()
+ )}
+
+
+
+
+
+
+
+
+
+
+ {service.serviceType === 'HELM' && (
+
+ )}
+
+ )
+
+ const cell = match({ service })
+ .with({ service: P.intersection({ serviceType: 'JOB' }, { source: P.when(isJobGitSource) }) }, ({ service }) => {
+ const {
+ source: { docker },
+ } = service
+ return gitInfo(service, docker?.git_repository)
+ })
+ .with(
+ { service: P.intersection({ serviceType: 'JOB' }, { source: P.when(isJobContainerSource) }) },
+ ({
+ service: {
+ source: { image },
+ },
+ }) => containerInfo(image)
+ )
+ .with({ service: { serviceType: 'APPLICATION' } }, ({ service }) => gitInfo(service, service.git_repository))
+ .with({ service: { serviceType: 'CONTAINER' } }, ({ service: { image_name, tag, registry } }) =>
+ containerInfo({ image_name, tag, registry })
+ )
+ .with({ service: { serviceType: 'DATABASE' } }, ({ service: { accessibility, mode, type, version } }) =>
+ datasourceInfo({ accessibility, mode, type, version })
+ )
+ .with({ service: P.intersection({ serviceType: 'HELM' }, { source: P.when(isHelmGitSource) }) }, ({ service }) => {
+ const {
+ source: { git },
+ } = service
+ return gitInfo(service, git?.git_repository)
+ })
+ .with(
+ { service: P.intersection({ serviceType: 'HELM' }, { source: P.when(isHelmRepositorySource) }) },
+ ({
+ service: {
+ source: { repository },
+ },
+ }) => helmInfo(repository)
+ )
+ .with({ service: { serviceType: 'TERRAFORM' } }, ({ service }) => {
+ return gitInfo(service, service?.terraform_files_source?.git?.git_repository)
+ })
+ .exhaustive()
+ return cell
+}
diff --git a/libs/domains/services/feature/src/lib/service-list/service-list.tsx b/libs/domains/services/feature/src/lib/service-list/service-list.tsx
index fbf2b015936..039fa0a5956 100644
--- a/libs/domains/services/feature/src/lib/service-list/service-list.tsx
+++ b/libs/domains/services/feature/src/lib/service-list/service-list.tsx
@@ -11,309 +11,32 @@ import {
getSortedRowModel,
useReactTable,
} from '@tanstack/react-table'
-import {
- type ApplicationGitRepository,
- type ContainerResponse,
- type Database,
- type Environment,
- type HelmSourceRepositoryResponse,
- type Status,
-} from 'qovery-typescript-axios'
-import { ServiceSubActionDto } from 'qovery-ws-typescript-axios'
+import { type Environment } from 'qovery-typescript-axios'
import { type ComponentProps, Fragment, useMemo, useState } from 'react'
-import { P, match } from 'ts-pattern'
-import {
- type AnyService,
- type Application,
- type Helm,
- type Job,
- type Terraform,
-} from '@qovery/domains/services/data-access'
-import {
- IconEnum,
- ServiceTypeEnum,
- isHelmGitSource,
- isHelmRepositorySource,
- isJobContainerSource,
- isJobGitSource,
-} from '@qovery/shared/enums'
+import { match } from 'ts-pattern'
+import { ServiceTypeEnum } from '@qovery/shared/enums'
import {
- APPLICATION_GENERAL_URL,
APPLICATION_URL,
- CLUSTER_URL,
DATABASE_GENERAL_URL,
DATABASE_URL,
- DEPLOYMENT_LOGS_VERSION_URL,
- ENVIRONMENT_LOGS_URL,
SERVICES_GENERAL_URL,
SERVICES_NEW_URL,
SERVICES_URL,
} from '@qovery/shared/routes'
-import {
- AnimatedGradientText,
- Badge,
- Button,
- Checkbox,
- EmptyState,
- ExternalLink,
- Icon,
- Link,
- Skeleton,
- StatusChip,
- TableFilter,
- TablePrimitives,
- Tooltip,
- Truncate,
-} from '@qovery/shared/ui'
-import { dateUTCString, timeAgo } from '@qovery/shared/util-dates'
-import { buildGitProviderUrl } from '@qovery/shared/util-git'
-import {
- containerRegistryKindToIcon,
- formatCronExpression,
- pluralize,
- twMerge,
- upperCaseFirstLetter,
-} from '@qovery/shared/util-js'
-import { useCheckRunningStatusClosed } from '../hooks/use-check-running-status-closed/use-check-running-status-closed'
-import { useServices } from '../hooks/use-services/use-services'
-import { LastCommit } from '../last-commit/last-commit'
-import LastVersion from '../last-version/last-version'
-import { ServiceActionToolbar } from '../service-action-toolbar/service-action-toolbar'
+import { Checkbox, EmptyState, Icon, Link, TableFilter, TablePrimitives, Truncate } from '@qovery/shared/ui'
+import { twMerge } from '@qovery/shared/util-js'
+import useServices from '../hooks/use-services/use-services'
import { ServiceAvatar } from '../service-avatar/service-avatar'
-import { ServiceLinksPopover } from '../service-links-popover/service-links-popover'
-import { ServiceTemplateIndicator } from '../service-template-indicator/service-template-indicator'
import { ServiceListActionBar } from './service-list-action-bar'
+import {
+ ServiceLastDeploymentCell,
+ ServiceNameCell,
+ ServiceRunningStatusCell,
+ ServiceVersionCell,
+} from './service-list-cells'
const { Table } = TablePrimitives
-function ServiceNameCell({
- service,
- environment,
- deploymentStatus,
-}: {
- service: AnyService
- environment: Environment
- deploymentStatus?: Status
-}) {
- const navigate = useNavigate()
-
- const deploymentRequestsCount = Number(deploymentStatus?.deployment_requests_count)
-
- const serviceLink = match(service)
- .with(
- { serviceType: ServiceTypeEnum.DATABASE },
- ({ id }) =>
- DATABASE_URL(environment.organization.id, environment.project.id, service.environment.id, id) +
- DATABASE_GENERAL_URL
- )
- .otherwise(
- ({ id }) =>
- APPLICATION_URL(environment.organization.id, environment.project.id, service.environment.id, id) +
- SERVICES_GENERAL_URL
- )
-
- const LinkDeploymentStatus = () => {
- const environmentLog = ENVIRONMENT_LOGS_URL(environment.organization.id, environment.project.id, environment.id)
- const deploymentLog = DEPLOYMENT_LOGS_VERSION_URL(service.id, deploymentStatus?.execution_id)
- // const precheckLog = ENVIRONMENT_PRE_CHECK_LOGS_URL(deploymentStatus?.execution_id ?? '')
-
- return match(deploymentStatus?.state)
- .with('DEPLOYMENT_QUEUED', 'DELETE_QUEUED', 'STOP_QUEUED', 'RESTART_QUEUED', (s) => (
- {upperCaseFirstLetter(s).replace('_', ' ')}...
- ))
- .with('CANCELED', () => Last deployment aborted)
- .with('DEPLOYING', 'RESTARTING', 'BUILDING', 'DELETING', 'CANCELING', 'STOPPING', (s) => (
- e.stopPropagation()}
- >
-
-
- {upperCaseFirstLetter(s)}...
-
-
-
- ))
- .with('DEPLOYMENT_ERROR', 'DELETE_ERROR', 'STOP_ERROR', 'RESTART_ERROR', 'BUILD_ERROR', () => (
- e.stopPropagation()}
- >
- Last deployment failed
-
-
- ))
- .otherwise(() => null)
- }
-
- return (
-
-
-
-
-
- {match(service)
- .with({ serviceType: 'DATABASE' }, (db) => {
- return (
-
-
-
- e.stopPropagation()}
- >
- {db.name}
-
-
-
-
-
- )
- })
- .with({ serviceType: 'JOB' }, (job) => {
- const schedule = match(job)
- .with(
- { job_type: 'CRON' },
- ({ schedule }) =>
- `Triggered: ${formatCronExpression(schedule.cronjob?.scheduled_at)} (${schedule.cronjob?.timezone})`
- )
- .with({ job_type: 'LIFECYCLE' }, ({ schedule }) => {
- const actions = [
- schedule.on_start && 'Deploy',
- schedule.on_stop && 'Stop',
- schedule.on_delete && 'Delete',
- ]
- .filter(Boolean)
- .join(' - ')
- return actions ? `Triggered on: ${actions}` : undefined
- })
- .exhaustive()
-
- return (
-
-
-
- e.stopPropagation()}
- >
- {service.name}
-
-
-
-
-
-
-
-
-
-
- )
- })
- .otherwise(() => (
-
-
- e.stopPropagation()}
- >
- {service.name}
-
-
-
-
- ))}
-
- {deploymentRequestsCount > 0 && (
-
-
-
- {deploymentRequestsCount}
-
-
- )}
-
-
-
- {'auto_deploy' in service && service.auto_deploy && (
-
-
-
-
-
- )}
-
e.stopPropagation()}>
-
-
-
-
-
-
e.stopPropagation()}>
- undefined)
- .with(
- { serviceType: 'DATABASE', mode: 'CONTAINER' },
- () => () =>
- navigate({
- to:
- DATABASE_URL(environment.organization.id, environment.project.id, environment.id, service.id) +
- DATABASE_GENERAL_URL,
- state: {
- hasShell: true,
- } as any,
- })
- )
- .otherwise(
- () => () =>
- navigate({
- to:
- APPLICATION_URL(environment.organization.id, environment.project.id, environment.id, service.id) +
- APPLICATION_GENERAL_URL,
- state: {
- hasShell: true,
- } as any,
- })
- )}
- />
-
-
-
- )
-}
-
export interface ServiceListProps extends ComponentProps {
environment: Environment
}
@@ -325,10 +48,7 @@ export function ServiceList({ className, environment, ...props }: ServiceListPro
const projectId = environment.project.id || ''
const { data: services = [] } = useServices({ environmentId, suspense: true })
- const { data: checkRunningStatusClosed } = useCheckRunningStatusClosed({
- clusterId,
- environmentId,
- })
+
const [sorting, setSorting] = useState([])
const [rowSelection, setRowSelection] = useState({})
const navigate = useNavigate()
@@ -398,11 +118,13 @@ export function ServiceList({ className, environment, ...props }: ServiceListPro
},
cell: (info) => {
return (
-
+
+
+
)
},
}),
@@ -414,81 +136,14 @@ export function ServiceList({ className, environment, ...props }: ServiceListPro
filterFn: 'arrIncludesSome',
size: 15,
cell: (info) => {
- const service = info.row.original
- const link = match(service)
- .with(
- { serviceType: ServiceTypeEnum.DATABASE },
- ({ id }) => DATABASE_URL(organizationId, projectId, environmentId, id) + DATABASE_GENERAL_URL
- )
- .otherwise(({ id }) => APPLICATION_URL(organizationId, projectId, environmentId, id) + SERVICES_GENERAL_URL)
-
- const value = match(service.runningStatus.triggered_action)
- .with(
- { sub_action: ServiceSubActionDto.TERRAFORM_PLAN_ONLY },
- () => 'Plan ' + info.getValue()?.toLowerCase()
- )
- .with(
- { sub_action: ServiceSubActionDto.TERRAFORM_PLAN_AND_APPLY },
- () => 'Apply ' + info.getValue()?.toLowerCase()
- )
- .with(
- { sub_action: ServiceSubActionDto.TERRAFORM_MIGRATE_STATE },
- () => 'Migrate state ' + info.getValue()?.toLowerCase()
- )
- .with(
- { sub_action: ServiceSubActionDto.TERRAFORM_FORCE_UNLOCK_STATE },
- () => 'Force unlock ' + info.getValue()?.toLowerCase()
- )
- .with(
- { sub_action: ServiceSubActionDto.TERRAFORM_DESTROY },
- () => 'Destroy ' + info.getValue()?.toLocaleString()
- )
- .with({ sub_action: ServiceSubActionDto.NONE }, () => info.getValue())
- .with(undefined, () => info.getValue())
- .exhaustive()
-
- if (checkRunningStatusClosed) {
- return (
-
- e.stopPropagation()}
- className="gap-2 whitespace-nowrap text-sm"
- size="md"
- color="neutral"
- variant="outline"
- radius="full"
- >
-
- Status unavailable
-
-
- )
- }
-
return (
-
-
- e.stopPropagation()}
- className="gap-2 whitespace-nowrap text-sm"
- size="md"
- color="neutral"
- variant="outline"
- radius="full"
- >
- s.deploymentStatus?.state)
- .otherwise((s) => s.runningStatus?.state)}
- />
- {value}
-
-
-
+
)
},
}),
@@ -498,199 +153,9 @@ export function ServiceList({ className, environment, ...props }: ServiceListPro
enableSorting: false,
size: 30,
cell: (info) => {
- const service = info.row.original
-
- const gitInfo = (service: Application | Job | Helm | Terraform, gitRepository?: ApplicationGitRepository) =>
- gitRepository && (
- e.stopPropagation()}>
-
-
-
-
-
-
-
- {gitRepository.branch && gitRepository.url && (
-
-
-
-
-
-
- )}
-
-
-
- )
- const containerInfo = (containerImage?: Pick) =>
- containerImage && (
- e.stopPropagation()}>
-
-
-
-
- {containerImage.registry.name.length >= 20 && (
- <>
- {containerImage.registry.name}
- >
- )}{' '}
- {containerImage.registry.url}
-
- }
- >
-
- {containerImage.registry.name.length >= 20 ? (
-
- ) : (
- containerImage.registry.name.toLowerCase()
- )}
-
-
-
-
-
-
-
-
- {(service.serviceType === 'CONTAINER' ||
- (service.serviceType === 'JOB' && isJobContainerSource(service.source))) && (
-
- )}
-
- )
-
- const datasourceInfo = (datasource?: Pick) =>
- datasource && (
-
-
-
- {datasource.type.toLowerCase().replace('sql', 'SQL').replace('db', 'DB')}
-
-
- v
- {datasource.version}
-
-
- )
-
- const helmInfo = (helmRepository?: HelmSourceRepositoryResponse) =>
- helmRepository && (
-
-
e.stopPropagation()}>
-
-
-
- {helmRepository.repository?.name.length > 20 && (
- <>
- {helmRepository.repository?.name}
- >
- )}
- {helmRepository.repository?.url}
-
- }
- >
-
- {helmRepository.repository?.name.length > 20 ? (
-
- ) : (
- helmRepository.repository?.name.toLowerCase()
- )}
-
-
-
-
-
-
-
-
-
-
- {service.serviceType === 'HELM' && (
-
- )}
-
- )
-
- const cell = match({ service })
- .with(
- { service: P.intersection({ serviceType: 'JOB' }, { source: P.when(isJobGitSource) }) },
- ({ service }) => {
- const {
- source: { docker },
- } = service
- return gitInfo(service, docker?.git_repository)
- }
- )
- .with(
- { service: P.intersection({ serviceType: 'JOB' }, { source: P.when(isJobContainerSource) }) },
- ({
- service: {
- source: { image },
- },
- }) => containerInfo(image)
- )
- .with({ service: { serviceType: 'APPLICATION' } }, ({ service }) =>
- gitInfo(service, service.git_repository)
- )
- .with({ service: { serviceType: 'CONTAINER' } }, ({ service: { image_name, tag, registry } }) =>
- containerInfo({ image_name, tag, registry })
- )
- .with({ service: { serviceType: 'DATABASE' } }, ({ service: { accessibility, mode, type, version } }) =>
- datasourceInfo({ accessibility, mode, type, version })
- )
- .with(
- { service: P.intersection({ serviceType: 'HELM' }, { source: P.when(isHelmGitSource) }) },
- ({ service }) => {
- const {
- source: { git },
- } = service
- return gitInfo(service, git?.git_repository)
- }
- )
- .with(
- { service: P.intersection({ serviceType: 'HELM' }, { source: P.when(isHelmRepositorySource) }) },
- ({
- service: {
- source: { repository },
- },
- }) => helmInfo(repository)
- )
- .with({ service: { serviceType: 'TERRAFORM' } }, ({ service }) => {
- return gitInfo(service, service?.terraform_files_source?.git?.git_repository)
- })
- .exhaustive()
- return cell
+ return (
+
+ )
},
}),
columnHelper.accessor('deploymentStatus.last_deployment_date', {
@@ -699,34 +164,18 @@ export function ServiceList({ className, environment, ...props }: ServiceListPro
enableSorting: true,
size: 3,
cell: (info) => {
- const service = info.row.original
- const value = info.getValue()
- const linkLog =
- ENVIRONMENT_LOGS_URL(organizationId, projectId, environmentId) +
- DEPLOYMENT_LOGS_VERSION_URL(service?.id, service?.deploymentStatus?.execution_id)
-
- return value ? (
- event.stopPropagation()}
- >
-
- {timeAgo(new Date(value))}
-
-
-
- ) : (
- -
+ return (
+
)
},
}),
],
- [columnHelper, organizationId, projectId, environmentId, navigate]
+ [columnHelper, environment, clusterId, organizationId, projectId, environmentId]
)
const table = useReactTable({
diff --git a/libs/domains/services/feature/src/lib/service-remove-modal/service-remove-modal.tsx b/libs/domains/services/feature/src/lib/service-remove-modal/service-remove-modal.tsx
index c508b9b6d90..d9fa70fb22f 100644
--- a/libs/domains/services/feature/src/lib/service-remove-modal/service-remove-modal.tsx
+++ b/libs/domains/services/feature/src/lib/service-remove-modal/service-remove-modal.tsx
@@ -51,9 +51,9 @@ export function ServiceRemoveModal({
return (
-
{title}
+
{title}
-
+
{description ? (
description
) : (
@@ -77,18 +77,18 @@ export function ServiceRemoveModal({
))}
@@ -135,16 +135,16 @@ export function ServiceRemoveModal({
- This action cannot be undone, type "
+ This action cannot be undone, type "
{selectedAction?.id}
- " to confirm.
+ " to confirm.
, R
return (
- {variant === 'check' && }
+ {variant === 'check' && }
)