Skip to content

Commit

Permalink
fix(service-logs): display header during loading and add placeholder …
Browse files Browse the repository at this point in the history
…msg (#1745)

* fix(service-logs): display header during loading and add placeholder msg

* fix: update margin

* network indicator
  • Loading branch information
RemiBonnet authored Oct 31, 2024
1 parent 145c826 commit 8e22b67
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 58 deletions.
8 changes: 8 additions & 0 deletions __tests__/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,12 @@ jest.mock('@uidotdev/usehooks', () => ({
// Params are implicitly `any` and needed for the tests
// eslint-disable-next-line @typescript-eslint/no-explicit-any
useLocalStorage: (_: any, intialValue: any) => [intialValue, jest.fn()],
useNetworkState: () => ({
effectiveType: '4g',
downlink: 10,
rtt: 50,
saveData: false,
online: true,
type: 'wifi',
}),
}))
Original file line number Diff line number Diff line change
Expand Up @@ -175,16 +175,49 @@ export function ListServiceLogs({ environment, clusterId, serviceStatus, environ
.with('RUNNING', 'WARNING', () => true)
.otherwise(() => false)

function HeaderLogsComponent() {
return (
<HeaderLogs
type="SERVICE"
environment={environment}
serviceId={serviceId ?? ''}
serviceStatus={serviceStatus}
environmentStatus={environmentStatus}
>
<Link
as="button"
className="gap-1"
variant="surface"
to={
ENVIRONMENT_LOGS_URL(environment.organization.id, environment.project.id, environment.id) +
DEPLOYMENT_LOGS_URL(serviceId)
}
>
{match(service)
.with({ serviceType: 'DATABASE' }, (db) => db.mode === 'CONTAINER')
.otherwise(() => true) ? (
<ServiceStateChip className="mr-1" mode="deployment" environmentId={environment.id} serviceId={serviceId} />
) : null}
Go to latest deployment
<Icon iconName="arrow-right" />
</Link>
</HeaderLogs>
)
}

// Temporary solution with `includes` to handle the case where only one log with the message 'No pods found' is received.
if (!logs || logs.length === 0 || logs[0].message.includes('No pods found')) {
return (
<div className="p-1">
<div className="h-[calc(100vh-72px)] border border-neutral-500 bg-neutral-600 pt-11">
<ServiceLogsPlaceholder
serviceName={service?.name}
itemsLength={logs.length}
databaseMode={service?.serviceType === 'DATABASE' ? service.mode : undefined}
/>
<div className="h-[calc(100vh-72px)] border border-r-0 border-t-0 border-neutral-500 bg-neutral-600">
<HeaderLogsComponent />
<div className="h-[calc(100vh-136px)] border-r border-neutral-500 bg-neutral-600 pt-11">
<ServiceLogsPlaceholder
serviceName={service?.name}
itemsLength={logs.length}
databaseMode={service?.serviceType === 'DATABASE' ? service.mode : undefined}
/>
</div>
</div>
</div>
)
Expand All @@ -199,36 +232,7 @@ export function ListServiceLogs({ environment, clusterId, serviceStatus, environ
>
<div className="h-[calc(100vh-64px)] w-full max-w-[calc(100vw-64px)] overflow-hidden p-1">
<div className="relative h-full border border-r-0 border-t-0 border-neutral-500 bg-neutral-600">
<HeaderLogs
type="SERVICE"
environment={environment}
serviceId={serviceId ?? ''}
serviceStatus={serviceStatus}
environmentStatus={environmentStatus}
>
<Link
as="button"
className="gap-1"
variant="surface"
to={
ENVIRONMENT_LOGS_URL(environment.organization.id, environment.project.id, environment.id) +
DEPLOYMENT_LOGS_URL(serviceId)
}
>
{match(service)
.with({ serviceType: 'DATABASE' }, (db) => db.mode === 'CONTAINER')
.otherwise(() => true) ? (
<ServiceStateChip
className="mr-1"
mode="deployment"
environmentId={environment.id}
serviceId={serviceId}
/>
) : null}
Go to latest deployment
<Icon iconName="arrow-right" />
</Link>
</HeaderLogs>
<HeaderLogsComponent />
<div className="flex h-12 w-full items-center justify-between border-b border-neutral-500 px-4 py-2.5">
<div className="flex items-center gap-3">
<Button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { P, match } from 'ts-pattern'
import { useDeploymentStatus } from '@qovery/domains/services/feature'
import { DEPLOYMENT_LOGS_URL, ENVIRONMENT_LOGS_URL } from '@qovery/shared/routes'
import { Icon, Link, LoaderSpinner } from '@qovery/shared/ui'
import { useNetworkState } from '@qovery/shared/util-hooks'

export function LoaderPlaceholder() {
return (
Expand All @@ -25,6 +26,7 @@ export function ServiceLogsPlaceholder({ serviceName, databaseMode, itemsLength
const { data: deploymentStatus } = useDeploymentStatus({ environmentId, serviceId })
const { state: deploymentState } = deploymentStatus ?? {}
const [showPlaceholder, setShowPlaceholder] = useState(false)
const { effectiveType } = useNetworkState()

useEffect(() => {
const timer = setTimeout(() => {
Expand All @@ -40,29 +42,48 @@ export function ServiceLogsPlaceholder({ serviceName, databaseMode, itemsLength
itemsLength: 0,
deploymentState: P.when((state) => state !== 'READY' && state !== 'STOPPED'),
},
() => <LoaderPlaceholder />
)
.with({ itemsLength: 0, deploymentState: P.when((state) => state === 'READY' || state === 'STOPPED') }, () =>
showPlaceholder ? (
<div className="text-center">
<p className="mb-1 font-medium text-neutral-50">
No logs available for <span className="text-brand-400">{serviceName}</span>.
</p>
<p className="mb-2 text-sm font-normal text-neutral-300">Please check if the service is up and running.</p>
<Link
as="button"
size="sm"
color="neutral"
to={ENVIRONMENT_LOGS_URL(organizationId, projectId, environmentId) + DEPLOYMENT_LOGS_URL(serviceId)}
>
Go to latest deployment
<Icon iconName="arrow-right" className="ml-1" />
</Link>
() => (
<div>
<LoaderPlaceholder />
<div className="mt-4 flex flex-col gap-1">
{showPlaceholder && (
<p className="text-center text-sm font-medium text-neutral-300">
Processing is taking more than 10s <br /> No logs available, please check the service configuration
</p>
)}
{effectiveType !== undefined && effectiveType !== '4g' && (
<p className="text-center text-sm font-medium text-neutral-350">Your connection is slow.</p>
)}
</div>
</div>
) : (
<LoaderPlaceholder />
)
)
.with(
{
itemsLength: 0,
deploymentState: P.when((state) => state === 'READY' || state === 'STOPPED'),
},
() =>
showPlaceholder ? (
<div className="text-center">
<p className="mb-1 font-medium text-neutral-50">
No logs available for <span className="text-brand-400">{serviceName}</span>.
</p>
<p className="mb-4 text-sm font-normal text-neutral-300">Please check if the service is up and running.</p>
<Link
as="button"
size="sm"
color="neutral"
to={ENVIRONMENT_LOGS_URL(organizationId, projectId, environmentId) + DEPLOYMENT_LOGS_URL(serviceId)}
>
Go to latest deployment
<Icon iconName="arrow-right" className="ml-1" />
</Link>
</div>
) : (
<LoaderPlaceholder />
)
)
.otherwise(() => (
<div className="text-center">
<p className="mb-1 font-medium text-neutral-50">
Expand Down
11 changes: 9 additions & 2 deletions libs/shared/util-hooks/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
import { useClickAway, useCopyToClipboard, useDebounce, useDocumentTitle, useLocalStorage } from '@uidotdev/usehooks'
import {
useClickAway,
useCopyToClipboard,
useDebounce,
useDocumentTitle,
useLocalStorage,
useNetworkState,
} from '@uidotdev/usehooks'

// NOTE: if you export from `@uidotdev/usehooks`, you need to mock it on the `mocks.ts` file for tests
export { useDocumentTitle, useClickAway, useCopyToClipboard, useDebounce, useLocalStorage }
export { useDocumentTitle, useClickAway, useCopyToClipboard, useDebounce, useLocalStorage, useNetworkState }

export * from './lib/use-format-hotkeys/use-format-hotkeys'

0 comments on commit 8e22b67

Please sign in to comment.