fix(webapp): derive expiry status from loader time
This commit is contained in:
+12
-4
@@ -173,6 +173,7 @@ export const loader = dashboardLoader(
|
||||
additionalApiKeyIssuanceEnabled,
|
||||
isRbacPluginAvailable,
|
||||
showRevoked: searchParams.showRevoked ?? false,
|
||||
loadedAt: Date.now(),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
@@ -308,6 +309,7 @@ export default function Page() {
|
||||
hasVercelIntegration,
|
||||
availableTasks,
|
||||
presets,
|
||||
loadedAt,
|
||||
} = useTypedLoaderData<typeof loader>();
|
||||
|
||||
const apiKeyEnvironmentLabel = {
|
||||
@@ -398,7 +400,7 @@ export default function Page() {
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<ApiKeyStatus />
|
||||
<ApiKeyStatus now={loadedAt} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<ApiKeyAccess label="No restrictions" />
|
||||
@@ -424,7 +426,7 @@ export default function Page() {
|
||||
|
||||
{apiKeys.map((apiKey) => {
|
||||
const isExpired = apiKey.expiresAt
|
||||
? new Date(apiKey.expiresAt).getTime() <= Date.now()
|
||||
? new Date(apiKey.expiresAt).getTime() <= loadedAt
|
||||
: false;
|
||||
const cannotAuthenticate = Boolean(apiKey.revokedAt) || isExpired;
|
||||
const cannotRevoke = Boolean(apiKey.revokedAt) || isExpired;
|
||||
@@ -445,7 +447,11 @@ export default function Page() {
|
||||
<span className="font-mono text-text-dimmed">{apiKey.obfuscated}</span>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<ApiKeyStatus revokedAt={apiKey.revokedAt} expiresAt={apiKey.expiresAt} />
|
||||
<ApiKeyStatus
|
||||
revokedAt={apiKey.revokedAt}
|
||||
expiresAt={apiKey.expiresAt}
|
||||
now={loadedAt}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<ApiKeyAccess
|
||||
@@ -1338,9 +1344,11 @@ function ApiKeyAccess({
|
||||
function ApiKeyStatus({
|
||||
revokedAt,
|
||||
expiresAt,
|
||||
now,
|
||||
}: {
|
||||
revokedAt?: Date | string | null;
|
||||
expiresAt?: Date | string | null;
|
||||
now: number;
|
||||
}) {
|
||||
if (revokedAt) {
|
||||
return (
|
||||
@@ -1351,7 +1359,7 @@ function ApiKeyStatus({
|
||||
);
|
||||
}
|
||||
|
||||
if (expiresAt && new Date(expiresAt).getTime() <= Date.now()) {
|
||||
if (expiresAt && new Date(expiresAt).getTime() <= now) {
|
||||
return (
|
||||
<div className="flex items-center gap-1 text-xs text-text-dimmed">
|
||||
<ExclamationTriangleIcon className="size-4" />
|
||||
|
||||
+25
-14
@@ -115,21 +115,18 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
|
||||
throw new Response("Session not found", { status: 404 });
|
||||
}
|
||||
|
||||
return typedjson({ session });
|
||||
return typedjson({ session, loadedAt: Date.now() });
|
||||
};
|
||||
|
||||
export default function Page() {
|
||||
const { session } = useTypedLoaderData<typeof loader>();
|
||||
const { session, loadedAt } = useTypedLoaderData<typeof loader>();
|
||||
const organization = useOrganization();
|
||||
const project = useProject();
|
||||
const environment = useEnvironment();
|
||||
|
||||
const isExpired = session.expiresAt != null && new Date(session.expiresAt).getTime() < loadedAt;
|
||||
const status: SessionStatus =
|
||||
session.closedAt != null
|
||||
? "CLOSED"
|
||||
: session.expiresAt != null && new Date(session.expiresAt).getTime() < Date.now()
|
||||
? "EXPIRED"
|
||||
: "ACTIVE";
|
||||
session.closedAt != null ? "CLOSED" : isExpired ? "EXPIRED" : "ACTIVE";
|
||||
|
||||
const displayId = session.externalId ?? session.friendlyId;
|
||||
const sessionsPath = v3SessionsPath(organization, project, environment);
|
||||
@@ -170,7 +167,7 @@ export default function Page() {
|
||||
default="420px"
|
||||
className="overflow-hidden"
|
||||
>
|
||||
<InspectorPane session={session} status={status} />
|
||||
<InspectorPane session={session} status={status} isExpired={isExpired} />
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</PageBody>
|
||||
@@ -712,7 +709,15 @@ function MergedStreamRow({
|
||||
);
|
||||
}
|
||||
|
||||
function InspectorPane({ session, status }: { session: LoadedSession; status: SessionStatus }) {
|
||||
function InspectorPane({
|
||||
session,
|
||||
status,
|
||||
isExpired,
|
||||
}: {
|
||||
session: LoadedSession;
|
||||
status: SessionStatus;
|
||||
isExpired: boolean;
|
||||
}) {
|
||||
const { value, replace } = useSearchParams();
|
||||
const tab = value("tab") ?? "overview";
|
||||
const organization = useOrganization();
|
||||
@@ -761,7 +766,7 @@ function InspectorPane({ session, status }: { session: LoadedSession; status: Se
|
||||
</div>
|
||||
<div className="overflow-y-auto px-3 py-3 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-surface-control">
|
||||
{tab === "overview" ? (
|
||||
<OverviewTab session={session} status={status} />
|
||||
<OverviewTab session={session} status={status} isExpired={isExpired} />
|
||||
) : tab === "runs" ? (
|
||||
<RunsTab session={session} status={status} allRunsPath={allRunsPath} />
|
||||
) : (
|
||||
@@ -772,7 +777,15 @@ function InspectorPane({ session, status }: { session: LoadedSession; status: Se
|
||||
);
|
||||
}
|
||||
|
||||
function OverviewTab({ session, status }: { session: LoadedSession; status: SessionStatus }) {
|
||||
function OverviewTab({
|
||||
session,
|
||||
status,
|
||||
isExpired,
|
||||
}: {
|
||||
session: LoadedSession;
|
||||
status: SessionStatus;
|
||||
isExpired: boolean;
|
||||
}) {
|
||||
const organization = useOrganization();
|
||||
const project = useProject();
|
||||
const environment = useEnvironment();
|
||||
@@ -892,9 +905,7 @@ function OverviewTab({ session, status }: { session: LoadedSession; status: Sess
|
||||
</Property.Item>
|
||||
{session.expiresAt ? (
|
||||
<Property.Item>
|
||||
<Property.Label>
|
||||
{new Date(session.expiresAt).getTime() < Date.now() ? "Expired" : "Expires"}
|
||||
</Property.Label>
|
||||
<Property.Label>{isExpired ? "Expired" : "Expires"}</Property.Label>
|
||||
<Property.Value>
|
||||
<DateTime date={session.expiresAt} />
|
||||
</Property.Value>
|
||||
|
||||
Reference in New Issue
Block a user