mirror of
https://github.com/graphql-hive/console
synced 2026-04-21 14:37:17 +00:00
feat(app-deployments): add createdAt, activatedAt, retiredAt fields and UI/UX improvements (#7669)
This commit is contained in:
parent
5b24204550
commit
a6f5ac4cc6
15 changed files with 323 additions and 31 deletions
5
.changeset/stupid-bobcats-switch.md
Normal file
5
.changeset/stupid-bobcats-switch.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'hive': patch
|
||||
---
|
||||
|
||||
Add `lastUsed`, `createdAt`, `activatedAt`, and `status` columns to app deployments tables. Fix broken text colors on multiple pages after the recent color palette overhaul.
|
||||
|
|
@ -17,6 +17,14 @@ export default gql`
|
|||
"""
|
||||
createdAt: DateTime! @tag(name: "public")
|
||||
"""
|
||||
The timestamp when the app deployment was activated.
|
||||
"""
|
||||
activatedAt: DateTime @tag(name: "public")
|
||||
"""
|
||||
The timestamp when the app deployment was retired. Only present for retired deployments.
|
||||
"""
|
||||
retiredAt: DateTime @tag(name: "public")
|
||||
"""
|
||||
The last time a GraphQL request that used the app deployment was reported.
|
||||
"""
|
||||
lastUsed: DateTime @tag(name: "public")
|
||||
|
|
|
|||
|
|
@ -1097,6 +1097,46 @@ export class AppDeployments {
|
|||
activeDeployments.map(d => [d.appDeploymentId, { name: d.appName, version: d.appVersion }]),
|
||||
);
|
||||
|
||||
const deploymentIds = activeDeployments.map(d => d.appDeploymentId);
|
||||
let timestampsResult;
|
||||
try {
|
||||
timestampsResult = await this.pool.query<{
|
||||
id: string;
|
||||
createdAt: string;
|
||||
activatedAt: string | null;
|
||||
retiredAt: string | null;
|
||||
}>(
|
||||
sql`
|
||||
SELECT
|
||||
"id",
|
||||
to_json("created_at") AS "createdAt",
|
||||
to_json("activated_at") AS "activatedAt",
|
||||
to_json("retired_at") AS "retiredAt"
|
||||
FROM "app_deployments"
|
||||
WHERE "id" = ANY(${sql.array(deploymentIds, 'uuid')})
|
||||
`,
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
'Failed to fetch deployment timestamps from postgres (targetId=%s, deploymentCount=%d): %s',
|
||||
args.targetId,
|
||||
deploymentIds.length,
|
||||
error instanceof Error ? error.message : String(error),
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
|
||||
const deploymentTimestamps = new Map(
|
||||
timestampsResult.rows.map(row => [
|
||||
row.id,
|
||||
{
|
||||
createdAt: row.createdAt,
|
||||
activatedAt: row.activatedAt,
|
||||
retiredAt: row.retiredAt,
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
// Count total affected deployments
|
||||
let countResult;
|
||||
try {
|
||||
|
|
@ -1355,11 +1395,15 @@ export class AppDeployments {
|
|||
}
|
||||
}
|
||||
|
||||
const timestamps = deploymentTimestamps.get(deploymentId);
|
||||
deployments.push({
|
||||
appDeployment: {
|
||||
id: deploymentId,
|
||||
name: info.name,
|
||||
version: info.version,
|
||||
createdAt: timestamps?.createdAt ?? null,
|
||||
activatedAt: timestamps?.activatedAt ?? null,
|
||||
retiredAt: timestamps?.retiredAt ?? null,
|
||||
},
|
||||
affectedOperationsByCoordinate: operations,
|
||||
countByCoordinate: coordCounts ? Object.fromEntries(coordCounts) : {},
|
||||
|
|
|
|||
|
|
@ -315,6 +315,10 @@ export type SchemaChangeAffectedAppDeploymentMapper = {
|
|||
id: string;
|
||||
name: string;
|
||||
version: string;
|
||||
createdAt: string | null;
|
||||
activatedAt: string | null;
|
||||
retiredAt: string | null;
|
||||
status: 'pending' | 'active' | 'retired';
|
||||
operations: Array<{
|
||||
hash: string;
|
||||
name: string | null;
|
||||
|
|
|
|||
|
|
@ -605,6 +605,26 @@ export default gql`
|
|||
"""
|
||||
version: String! @tag(name: "public")
|
||||
"""
|
||||
The timestamp when the app deployment was created.
|
||||
"""
|
||||
createdAt: DateTime @tag(name: "public")
|
||||
"""
|
||||
The timestamp when the app deployment was activated.
|
||||
"""
|
||||
activatedAt: DateTime @tag(name: "public")
|
||||
"""
|
||||
The current status of the app deployment.
|
||||
"""
|
||||
status: AppDeploymentStatus!
|
||||
"""
|
||||
The timestamp when the app deployment was retired. Only present for retired deployments.
|
||||
"""
|
||||
retiredAt: DateTime @tag(name: "public")
|
||||
"""
|
||||
The last time a GraphQL request that used the app deployment was reported.
|
||||
"""
|
||||
lastUsed: DateTime @tag(name: "public")
|
||||
"""
|
||||
The operations within this app deployment that use the affected schema coordinate.
|
||||
"""
|
||||
affectedOperations(
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@ export type AffectedAppDeployment = {
|
|||
id: string;
|
||||
name: string;
|
||||
version: string;
|
||||
createdAt: string | null;
|
||||
activatedAt: string | null;
|
||||
retiredAt: string | null;
|
||||
};
|
||||
affectedOperationsByCoordinate: Record<string, Array<{ hash: string; name: string | null }>>;
|
||||
countByCoordinate: Record<string, number>;
|
||||
|
|
@ -714,6 +717,9 @@ export class RegistryChecks {
|
|||
id: d.appDeployment.id,
|
||||
name: d.appDeployment.name,
|
||||
version: d.appDeployment.version,
|
||||
createdAt: d.appDeployment.createdAt,
|
||||
activatedAt: d.appDeployment.activatedAt,
|
||||
retiredAt: d.appDeployment.retiredAt,
|
||||
affectedOperations: d.affectedOperationsByCoordinate[coordinate],
|
||||
}));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,10 @@ export const SchemaChange: Pick<
|
|||
id: d.id,
|
||||
name: d.name,
|
||||
version: d.version,
|
||||
createdAt: d.createdAt ?? null,
|
||||
activatedAt: d.activatedAt ?? null,
|
||||
retiredAt: d.retiredAt ?? null,
|
||||
status: d.retiredAt ? ('retired' as const) : ('active' as const),
|
||||
operations: d.affectedOperations,
|
||||
totalOperations: d.affectedOperations.length,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
import { AppDeploymentsManager } from '../../app-deployments/providers/app-deployments-manager';
|
||||
import type { SchemaChangeAffectedAppDeploymentResolvers } from './../../../__generated__/types';
|
||||
|
||||
export const SchemaChangeAffectedAppDeployment: SchemaChangeAffectedAppDeploymentResolvers = {
|
||||
lastUsed: async (deployment, _, { injector }) => {
|
||||
return injector
|
||||
.get(AppDeploymentsManager)
|
||||
.getLastUsedForAppDeployment({ id: deployment.id } as any);
|
||||
},
|
||||
affectedOperations: (deployment, args) => {
|
||||
const allOperations = (deployment.operations ?? []).map(op => ({
|
||||
hash: op.hash,
|
||||
|
|
|
|||
|
|
@ -1304,6 +1304,9 @@ export const HiveSchemaChangeModel = z
|
|||
id: z.string(),
|
||||
name: z.string(),
|
||||
version: z.string(),
|
||||
createdAt: z.string().nullable().optional(),
|
||||
activatedAt: z.string().nullable().optional(),
|
||||
retiredAt: z.string().nullable().optional(),
|
||||
affectedOperations: z.array(
|
||||
z.object({
|
||||
hash: z.string(),
|
||||
|
|
@ -1344,6 +1347,9 @@ export const HiveSchemaChangeModel = z
|
|||
id: string;
|
||||
name: string;
|
||||
version: string;
|
||||
createdAt?: string | null;
|
||||
activatedAt?: string | null;
|
||||
retiredAt?: string | null;
|
||||
affectedOperations: { hash: string; name: string | null }[];
|
||||
}[]
|
||||
| null;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import {
|
|||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { TimeAgo } from '@/components/v2';
|
||||
import { FragmentType, graphql, useFragment } from '@/gql';
|
||||
import { SeverityLevelType } from '@/gql/graphql';
|
||||
import { CheckCircledIcon, InfoCircledIcon } from '@radix-ui/react-icons';
|
||||
|
|
@ -101,6 +102,8 @@ const ChangesBlock_SchemaChangeWithUsageFragment = graphql(`
|
|||
id
|
||||
name
|
||||
version
|
||||
activatedAt
|
||||
lastUsed
|
||||
affectedOperations(first: 5) {
|
||||
edges {
|
||||
cursor
|
||||
|
|
@ -243,7 +246,7 @@ function ChangeItem(
|
|||
{'usageStatistics' in change && change.usageStatistics && (
|
||||
<>
|
||||
{' '}
|
||||
<span className="bg-neutral-5 inline-flex items-center space-x-1 rounded-sm px-2 py-1 align-middle font-bold">
|
||||
<span className="bg-neutral-5 inline-flex items-center space-x-1 rounded-sm px-2 py-1 align-middle font-bold text-red-400">
|
||||
<PulseIcon className="h-4 stroke-[1px]" />
|
||||
<span className="text-xs">
|
||||
{change.usageStatistics.topAffectedOperations.length}
|
||||
|
|
@ -263,7 +266,7 @@ function ChangeItem(
|
|||
{'affectedAppDeployments' in change && change.affectedAppDeployments?.totalCount ? (
|
||||
<>
|
||||
{' '}
|
||||
<span className="inline-flex items-center space-x-1 rounded-sm bg-orange-500 px-2 py-1 align-middle font-bold">
|
||||
<span className="text-neutral-1 inline-flex items-center space-x-1 rounded-sm bg-orange-500 px-2 py-1 align-middle font-bold">
|
||||
<BoxIcon className="size-4 stroke-[2px]" />
|
||||
<span className="text-xs">
|
||||
{change.affectedAppDeployments.totalCount}{' '}
|
||||
|
|
@ -425,13 +428,16 @@ function ChangeItem(
|
|||
Affected App Deployments
|
||||
</h4>
|
||||
<p className="text-neutral-10 mb-2 text-sm">
|
||||
Top 5 active app deployments that have operations using this schema coordinate.
|
||||
Top 5 active app deployments that have operations using this schema coordinate
|
||||
(snapshot from when the check was run).
|
||||
</p>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-[200px]">App Name</TableHead>
|
||||
<TableHead>Version</TableHead>
|
||||
<TableHead>Activated</TableHead>
|
||||
<TableHead className="text-end">Last Used</TableHead>
|
||||
<TableHead className="text-right">Affected Operations</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
|
|
@ -455,6 +461,33 @@ function ChangeItem(
|
|||
</Link>
|
||||
</TableCell>
|
||||
<TableCell>{deployment.version}</TableCell>
|
||||
<TableCell>
|
||||
{deployment.activatedAt ? (
|
||||
<span className="text-neutral-11 cursor-help text-xs">
|
||||
<TimeAgo date={deployment.activatedAt} />
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-neutral-10 text-xs">—</span>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell className="text-end">
|
||||
{deployment.lastUsed ? (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<span className="text-neutral-11 cursor-help text-xs">
|
||||
<TimeAgo date={deployment.lastUsed} />
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{format(deployment.lastUsed, 'MMM d, yyyy HH:mm:ss')}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
) : (
|
||||
<span className="text-neutral-10 text-xs">—</span>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
|
|
@ -511,7 +544,7 @@ function ChangeItem(
|
|||
schemaCheckId: props.schemaCheckId,
|
||||
}}
|
||||
search={{ coordinate: change.path?.join('.') }}
|
||||
className="text-neutral-2 mt-2 block text-sm hover:underline"
|
||||
className="mt-2 block text-sm text-orange-500 hover:underline"
|
||||
>
|
||||
View all ({change.affectedAppDeployments.totalCount}) affected app deployments
|
||||
</Link>
|
||||
|
|
@ -523,13 +556,16 @@ function ChangeItem(
|
|||
<div>
|
||||
<h4 className="text-neutral-12 mb-1 text-sm font-medium">Affected App Deployments</h4>
|
||||
<p className="text-neutral-10 mb-2 text-sm">
|
||||
Top 5 active app deployments that have operations using this schema coordinate.
|
||||
Top 5 active app deployments that have operations using this schema coordinate
|
||||
(snapshot from when the check was run).
|
||||
</p>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-[200px]">App Name</TableHead>
|
||||
<TableHead>Version</TableHead>
|
||||
<TableHead>Activated</TableHead>
|
||||
<TableHead className="text-end">Last Used</TableHead>
|
||||
<TableHead className="text-right">Affected Operations</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
|
|
@ -553,6 +589,33 @@ function ChangeItem(
|
|||
</Link>
|
||||
</TableCell>
|
||||
<TableCell>{deployment.version}</TableCell>
|
||||
<TableCell>
|
||||
{deployment.activatedAt ? (
|
||||
<span className="text-neutral-11 cursor-help text-xs">
|
||||
<TimeAgo date={deployment.activatedAt} />
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-neutral-10 text-xs">—</span>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell className="text-end">
|
||||
{deployment.lastUsed ? (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<span className="text-neutral-11 cursor-help text-xs">
|
||||
<TimeAgo date={deployment.lastUsed} />
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{format(deployment.lastUsed, 'MMM d, yyyy HH:mm:ss')}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
) : (
|
||||
<span className="text-neutral-10 text-xs">—</span>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
|
|
@ -606,7 +669,7 @@ function ChangeItem(
|
|||
schemaCheckId: props.schemaCheckId,
|
||||
}}
|
||||
search={{ coordinate: change.path?.join('.') }}
|
||||
className="text-neutral-2 mt-2 block text-sm hover:underline"
|
||||
className="mt-2 block text-sm text-orange-500 hover:underline"
|
||||
>
|
||||
View all ({change.affectedAppDeployments.totalCount}) affected app deployments
|
||||
</Link>
|
||||
|
|
|
|||
18
packages/web/app/src/components/ui/date-with-time-ago.tsx
Normal file
18
packages/web/app/src/components/ui/date-with-time-ago.tsx
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { format } from 'date-fns';
|
||||
import { TimeAgo } from '@/components/v2';
|
||||
|
||||
export function DateWithTimeAgo(props: {
|
||||
date: string;
|
||||
dateFormatStr?: string;
|
||||
}): React.ReactElement {
|
||||
const { date, dateFormatStr = 'MMM d, yyyy' } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
{format(date, dateFormatStr)}{' '}
|
||||
<span className="text-neutral-10 font-normal">
|
||||
(<TimeAgo date={date} />)
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
18
packages/web/app/src/components/ui/deployment-status.tsx
Normal file
18
packages/web/app/src/components/ui/deployment-status.tsx
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { format } from 'date-fns';
|
||||
|
||||
export function DeploymentStatusLabel(props: {
|
||||
status: string;
|
||||
retiredAt?: string | null;
|
||||
}): React.ReactElement {
|
||||
const { status, retiredAt } = props;
|
||||
|
||||
if (status === 'retired' && retiredAt) {
|
||||
return (
|
||||
<span>
|
||||
{status} ({format(retiredAt, 'MMM d, yyyy HH:mm:ss')})
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return <>{status}</>;
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
import { format } from 'date-fns';
|
||||
import { LoaderCircleIcon } from 'lucide-react';
|
||||
import { useClient, useQuery } from 'urql';
|
||||
import { AppFilter } from '@/components/apps/AppFilter';
|
||||
|
|
@ -6,6 +7,7 @@ import { NotFoundContent } from '@/components/common/not-found-content';
|
|||
import { Page, TargetLayout } from '@/components/layouts/target';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { CardDescription } from '@/components/ui/card';
|
||||
import { DateWithTimeAgo } from '@/components/ui/date-with-time-ago';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
|
|
@ -27,7 +29,6 @@ import {
|
|||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { TimeAgo } from '@/components/v2';
|
||||
import { graphql } from '@/gql';
|
||||
import { AppDeploymentStatus } from '@/gql/graphql';
|
||||
import { useRedirect } from '@/lib/access/common';
|
||||
|
|
@ -61,6 +62,8 @@ const TargetAppsVersionQuery = graphql(`
|
|||
name
|
||||
version
|
||||
createdAt
|
||||
activatedAt
|
||||
retiredAt
|
||||
lastUsed
|
||||
totalDocumentCount
|
||||
status
|
||||
|
|
@ -277,7 +280,7 @@ function TargetAppVersionContent(props: {
|
|||
appName: props.appName,
|
||||
appVersion: props.appVersion,
|
||||
}}
|
||||
className="text-neutral-2 hover:underline"
|
||||
className="text-orange-500 hover:underline"
|
||||
>
|
||||
Clear filter
|
||||
</Link>
|
||||
|
|
@ -320,7 +323,14 @@ function TargetAppVersionContent(props: {
|
|||
appDeployment?.status === AppDeploymentStatus.Pending && 'text-neutral-11',
|
||||
)}
|
||||
>
|
||||
{appDeployment?.status.toUpperCase() ?? '...'}
|
||||
{appDeployment?.status === AppDeploymentStatus.Retired &&
|
||||
appDeployment?.retiredAt ? (
|
||||
<span>
|
||||
RETIRED ({format(appDeployment.retiredAt, 'MMM d, yyyy HH:mm:ss')})
|
||||
</span>
|
||||
) : (
|
||||
(appDeployment?.status.toUpperCase() ?? '...')
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
|
|
@ -329,20 +339,46 @@ function TargetAppVersionContent(props: {
|
|||
{appDeployment?.totalDocumentCount ?? '...'}
|
||||
</div>
|
||||
</div>
|
||||
<div className="min-w-0 text-xs">
|
||||
Created{' '}
|
||||
{appDeployment?.createdAt ? <TimeAgo date={appDeployment.createdAt} /> : '...'}
|
||||
<div className="min-w-0">
|
||||
<div className="text-xs">Created</div>
|
||||
<div className="text-neutral-12 text-sm font-semibold">
|
||||
{appDeployment?.createdAt ? (
|
||||
<DateWithTimeAgo
|
||||
date={appDeployment.createdAt}
|
||||
dateFormatStr="MMM d, yyyy HH:mm:ss"
|
||||
/>
|
||||
) : (
|
||||
'...'
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="min-w-0 text-xs">
|
||||
{data.fetching ? (
|
||||
'...'
|
||||
) : appDeployment?.lastUsed ? (
|
||||
<>
|
||||
Last Used <TimeAgo date={appDeployment.lastUsed} />
|
||||
</>
|
||||
) : (
|
||||
'No Usage Data'
|
||||
)}
|
||||
<div className="min-w-0">
|
||||
<div className="text-xs">Activated</div>
|
||||
<div className="text-neutral-12 text-sm font-semibold">
|
||||
{appDeployment?.activatedAt ? (
|
||||
<DateWithTimeAgo
|
||||
date={appDeployment.activatedAt}
|
||||
dateFormatStr="MMM d, yyyy HH:mm:ss"
|
||||
/>
|
||||
) : (
|
||||
<span className="text-neutral-10 font-normal">—</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<div className="text-xs">Last Used</div>
|
||||
<div className="text-neutral-12 text-sm font-semibold">
|
||||
{data.fetching ? (
|
||||
'...'
|
||||
) : appDeployment?.lastUsed ? (
|
||||
<DateWithTimeAgo
|
||||
date={appDeployment.lastUsed}
|
||||
dateFormatStr="MMM d, yyyy HH:mm:ss"
|
||||
/>
|
||||
) : (
|
||||
<span className="text-neutral-10 font-normal">No Usage Data</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import { Page, TargetLayout } from '@/components/layouts/target';
|
|||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { CardDescription } from '@/components/ui/card';
|
||||
import { DateWithTimeAgo } from '@/components/ui/date-with-time-ago';
|
||||
import { DeploymentStatusLabel } from '@/components/ui/deployment-status';
|
||||
import { EmptyList, NoSchemaVersion } from '@/components/ui/empty-list';
|
||||
import { Meta } from '@/components/ui/meta';
|
||||
import { SubPageLayoutHeader } from '@/components/ui/page-content-layout';
|
||||
|
|
@ -33,6 +35,9 @@ const AppTableRow_AppDeploymentFragment = graphql(`
|
|||
version
|
||||
status
|
||||
totalDocumentCount
|
||||
createdAt
|
||||
activatedAt
|
||||
retiredAt
|
||||
lastUsed
|
||||
}
|
||||
`);
|
||||
|
|
@ -142,24 +147,38 @@ function AppTableRow(props: {
|
|||
</TableCell>
|
||||
<TableCell className="hidden text-center sm:table-cell">
|
||||
<Badge className="text-xs" variant="secondary">
|
||||
{appDeployment.status}
|
||||
<DeploymentStatusLabel
|
||||
status={appDeployment.status}
|
||||
retiredAt={appDeployment.retiredAt}
|
||||
/>
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="text-center">{appDeployment.totalDocumentCount}</TableCell>
|
||||
<TableCell className="hidden text-center sm:table-cell">
|
||||
<span className="text-xs">
|
||||
<DateWithTimeAgo date={appDeployment.createdAt} />
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell className="hidden text-center sm:table-cell">
|
||||
{appDeployment.activatedAt ? (
|
||||
<span className="text-xs">
|
||||
<DateWithTimeAgo date={appDeployment.activatedAt} />
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-neutral-10 text-xs">—</span>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell className="text-end">
|
||||
{appDeployment.lastUsed ? (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<TimeAgo date={appDeployment.lastUsed} className="cursor-help text-xs" />{' '}
|
||||
<Badge className="cursor-help text-xs" variant="outline">
|
||||
<TimeAgo date={appDeployment.lastUsed} />
|
||||
</Badge>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>
|
||||
{'Last operation reported on '}
|
||||
{format(appDeployment.lastUsed, 'dd.MM.yyyy')}
|
||||
{' at '}
|
||||
{format(appDeployment.lastUsed, 'HH:mm')}
|
||||
</p>
|
||||
<p>{format(appDeployment.lastUsed, 'MMM d, yyyy HH:mm:ss')}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
|
|
@ -281,6 +300,8 @@ function TargetAppsView(props: {
|
|||
<TableHead className="hidden text-center sm:table-cell">
|
||||
Amount of Documents
|
||||
</TableHead>
|
||||
<TableHead className="hidden text-center sm:table-cell">Created</TableHead>
|
||||
<TableHead className="hidden text-center sm:table-cell">Activated</TableHead>
|
||||
<TableHead className="hidden text-end sm:table-cell">
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { useCallback, useMemo, useRef, useState } from 'react';
|
|||
import { useQuery } from 'urql';
|
||||
import { Page, TargetLayout } from '@/components/layouts/target';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { DateWithTimeAgo } from '@/components/ui/date-with-time-ago';
|
||||
import { EmptyList } from '@/components/ui/empty-list';
|
||||
import { Meta } from '@/components/ui/meta';
|
||||
import { SubPageLayoutHeader } from '@/components/ui/page-content-layout';
|
||||
|
|
@ -54,6 +55,9 @@ const AffectedDeploymentsQuery = graphql(`
|
|||
name
|
||||
version
|
||||
totalAffectedOperations
|
||||
activatedAt
|
||||
retiredAt
|
||||
lastUsed
|
||||
}
|
||||
}
|
||||
totalCount
|
||||
|
|
@ -80,6 +84,9 @@ const AffectedDeploymentsQuery = graphql(`
|
|||
name
|
||||
version
|
||||
totalAffectedOperations
|
||||
activatedAt
|
||||
retiredAt
|
||||
lastUsed
|
||||
}
|
||||
}
|
||||
totalCount
|
||||
|
|
@ -102,6 +109,9 @@ type AffectedDeployment = {
|
|||
name: string;
|
||||
version: string;
|
||||
totalOperations: number;
|
||||
activatedAt: string | null;
|
||||
retiredAt: string | null;
|
||||
lastUsed: string | null;
|
||||
};
|
||||
|
||||
const PAGE_SIZE = 20;
|
||||
|
|
@ -167,6 +177,9 @@ function TargetChecksAffectedDeploymentsContent(props: {
|
|||
name: edge.node.name,
|
||||
version: edge.node.version,
|
||||
totalOperations: edge.node.totalAffectedOperations,
|
||||
activatedAt: edge.node.activatedAt ?? null,
|
||||
retiredAt: edge.node.retiredAt ?? null,
|
||||
lastUsed: edge.node.lastUsed ?? null,
|
||||
}),
|
||||
) ?? [];
|
||||
|
||||
|
|
@ -231,7 +244,7 @@ function TargetChecksAffectedDeploymentsContent(props: {
|
|||
targetSlug: props.targetSlug,
|
||||
schemaCheckId: props.schemaCheckId,
|
||||
}}
|
||||
className="text-neutral-2 hover:underline"
|
||||
className="text-orange-500 hover:underline"
|
||||
>
|
||||
Schema Check
|
||||
</Link>
|
||||
|
|
@ -277,6 +290,8 @@ function TargetChecksAffectedDeploymentsContent(props: {
|
|||
<TableRow>
|
||||
<TableHead className="w-[200px]">App Name</TableHead>
|
||||
<TableHead>Version</TableHead>
|
||||
<TableHead>Activated</TableHead>
|
||||
<TableHead>Last Used</TableHead>
|
||||
<TableHead className="text-right">Total Operations</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
|
|
@ -302,6 +317,24 @@ function TargetChecksAffectedDeploymentsContent(props: {
|
|||
</Link>
|
||||
</TableCell>
|
||||
<TableCell>{deployment.version}</TableCell>
|
||||
<TableCell>
|
||||
{deployment.activatedAt ? (
|
||||
<span className="text-xs">
|
||||
<DateWithTimeAgo date={deployment.activatedAt} />
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-neutral-10 text-xs">—</span>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{deployment.lastUsed ? (
|
||||
<span className="text-xs">
|
||||
<DateWithTimeAgo date={deployment.lastUsed} />
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-neutral-10 text-xs">—</span>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<Button variant="link" className="h-auto p-0" asChild>
|
||||
<Link
|
||||
|
|
|
|||
Loading…
Reference in a new issue