Add searching and sorting options to the list of projects (#5285)

This commit is contained in:
Kamil Kisiela 2024-07-30 14:15:30 +02:00 committed by GitHub
parent 2ec56a03bc
commit a62bcb15b6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 415 additions and 109 deletions

View file

@ -21,7 +21,7 @@ const buttonVariants = cva(
default: 'h-10 py-2 px-4',
sm: 'h-9 px-3 rounded-md',
lg: 'h-11 px-8 rounded-md',
icon: 'size-9',
icon: 'size-10',
'icon-sm': 'size-7',
},
},

View file

@ -2,15 +2,20 @@ import { ReactElement, useMemo, useRef } from 'react';
import { endOfDay, formatISO, startOfDay } from 'date-fns';
import * as echarts from 'echarts';
import ReactECharts from 'echarts-for-react';
import { Globe, History } from 'lucide-react';
import { Globe, History, MoveDownIcon, MoveUpIcon, SearchIcon } from 'lucide-react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { useQuery } from 'urql';
import { z } from 'zod';
import { OrganizationLayout, Page } from '@/components/layouts/organization';
import { Button } from '@/components/ui/button';
import { Card } from '@/components/ui/card';
import { EmptyList } from '@/components/ui/empty-list';
import { Input } from '@/components/ui/input';
import { Meta } from '@/components/ui/meta';
import { Subtitle, Title } from '@/components/ui/page';
import { QueryError } from '@/components/ui/query-error';
import { Select, SelectContent, SelectItem, SelectTrigger } from '@/components/ui/select';
import { Separator } from '@/components/ui/separator';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
import { FragmentType, graphql, useFragment } from '@/gql';
import { ProjectType } from '@/gql/graphql';
@ -18,7 +23,15 @@ import { subDays } from '@/lib/date-time';
import { useFormattedNumber } from '@/lib/hooks';
import { pluralize } from '@/lib/utils';
import { UTCDate } from '@date-fns/utc';
import { Link } from '@tanstack/react-router';
import { Link, useRouter } from '@tanstack/react-router';
export const OrganizationIndexRouteSearch = z.object({
search: z.string().optional(),
sortBy: z.enum(['requests', 'versions', 'name']).optional(),
sortOrder: z.enum(['asc', 'desc']).optional(),
});
type RouteSearchProps = z.infer<typeof OrganizationIndexRouteSearch>;
const ProjectCard_ProjectFragment = graphql(`
fragment ProjectCard_ProjectFragment on Project {
@ -240,13 +253,29 @@ const OrganizationProjectsPageQuery = graphql(`
}
`);
function OrganizationPageContent(props: { organizationId: string }) {
function OrganizationPageContent(
props: {
organizationId: string;
} & RouteSearchProps,
) {
const days = 14;
const period = useRef<{
from: string;
to: string;
}>();
// Sort by requests by default
const sortKey = props.sortBy ?? 'requests';
const sortOrder =
props.sortOrder === 'asc'
? -1
: // if the sort order is not set, sort by name in ascending order by default
!props.sortOrder && props.sortBy === 'name'
? -1
: // if the sort order is not set, sort in descending order by default
1;
if (!period.current) {
const now = new UTCDate();
const from = formatISO(startOfDay(subDays(now, days)));
@ -255,6 +284,8 @@ function OrganizationPageContent(props: { organizationId: string }) {
period.current = { from, to };
}
const router = useRouter();
const [query] = useQuery({
query: OrganizationProjectsPageQuery,
variables: {
@ -266,13 +297,13 @@ function OrganizationPageContent(props: { organizationId: string }) {
});
const currentOrganization = query.data?.organization?.organization;
const projects = query.data?.projects;
const projectsConnection = query.data?.projects;
const highestNumberOfRequests = useMemo(() => {
let highest = 10;
if (projects?.nodes.length) {
for (const project of projects.nodes) {
if (projectsConnection?.nodes.length) {
for (const project of projectsConnection.nodes) {
for (const dataPoint of project.requestsOverTime) {
if (dataPoint.value > highest) {
highest = dataPoint.value;
@ -282,7 +313,40 @@ function OrganizationPageContent(props: { organizationId: string }) {
}
return highest;
}, [projects]);
}, [projectsConnection]);
const projects = useMemo(() => {
if (!projectsConnection) {
return [];
}
const searchPhrase = props.search;
const newProjects = searchPhrase
? projectsConnection.nodes.filter(project =>
project.name.toLowerCase().includes(searchPhrase.toLowerCase()),
)
: projectsConnection.nodes.slice();
return newProjects.sort((a, b) => {
const diffRequests = b.totalRequests - a.totalRequests;
const diffVersions = b.schemaVersionsCount - a.schemaVersionsCount;
if (sortKey === 'requests' && diffRequests !== 0) {
return diffRequests * sortOrder;
}
if (sortKey === 'versions' && diffVersions !== 0) {
return diffVersions * sortOrder;
}
if (sortKey === 'name') {
return a.name.localeCompare(b.name) * sortOrder * -1;
}
// falls back to sort by name in ascending order
return a.name.localeCompare(b.name);
});
}, [projectsConnection, props.search, sortKey, sortOrder]);
if (query.error) {
return <QueryError organizationId={props.organizationId} error={query.error} />;
@ -296,12 +360,98 @@ function OrganizationPageContent(props: { organizationId: string }) {
>
<>
<div className="grow">
<div className="py-6">
<Title>Projects</Title>
<Subtitle>A list of available project in your organization.</Subtitle>
<div className="flex flex-row items-center justify-between py-6">
<div>
<Title>Projects</Title>
<Subtitle>A list of available project in your organization.</Subtitle>
</div>
<div>
<div className="flex flex-row items-center gap-x-2">
<div className="relative">
<SearchIcon className="text-muted-foreground absolute left-2.5 top-2.5 size-4" />
<Input
type="search"
placeholder="Search..."
value={props.search}
onChange={event => {
void router.navigate({
search(params) {
return {
...params,
search: event.target.value,
};
},
});
}}
className="bg-background w-full rounded-lg pl-8 md:w-[200px] lg:w-[336px]"
/>
</div>
<Separator orientation="vertical" className="mx-4 h-8" />
<Select
value={props.sortBy ?? 'requests'}
onValueChange={value => {
void router.navigate({
search(params) {
return {
...params,
sortBy: value,
};
},
});
}}
>
<SelectTrigger className="hover:bg-accent bg-transparent">
{props.sortBy === 'versions'
? 'Schema Versions'
: props.sortBy === 'name'
? 'Name'
: 'Requests'}
</SelectTrigger>
<SelectContent>
<SelectItem value="requests">
<div className="font-bold">Requests</div>
<div className="text-muted-foreground text-xs">
GraphQL requests made in the last {days} days.
</div>
</SelectItem>
<SelectItem value="versions">
<div className="font-bold">Schema Versions</div>
<div className="text-muted-foreground text-xs">
Schemas published in last {days} days.
</div>
</SelectItem>
<SelectItem value="name">
<div className="font-bold">Name</div>
<div className="text-muted-foreground text-xs">Sort by project name.</div>
</SelectItem>
</SelectContent>
</Select>
<Button
className="shrink-0"
variant="outline"
size="icon"
onClick={() => {
void router.navigate({
search(params) {
return {
...params,
sortOrder: props.sortOrder === 'asc' ? 'desc' : 'asc',
};
},
});
}}
>
{props.sortOrder === 'asc' ? (
<MoveUpIcon className="size-4" />
) : (
<MoveDownIcon className="size-4" />
)}
</Button>
</div>
</div>
</div>
{currentOrganization && projects ? (
projects.total === 0 ? (
{currentOrganization && projectsConnection ? (
projectsConnection.total === 0 ? (
<EmptyList
title="Hive is waiting for your first project"
description='You can create a project by clicking the "Create Project" button'
@ -309,31 +459,17 @@ function OrganizationPageContent(props: { organizationId: string }) {
/>
) : (
<div className="grid grid-cols-2 items-stretch gap-5 xl:grid-cols-3">
{projects.nodes
.sort((a, b) => {
const diffOperations = b.totalRequests - a.totalRequests;
if (diffOperations !== 0) {
return diffOperations;
}
const diffVersions = b.schemaVersionsCount - a.schemaVersionsCount;
if (diffVersions !== 0) {
return diffVersions;
}
return a.name.localeCompare(b.name);
})
.map(project => (
<ProjectCard
key={project.id}
cleanOrganizationId={currentOrganization.cleanId}
days={days}
highestNumberOfRequests={highestNumberOfRequests}
project={project}
requestsOverTime={project.requestsOverTime}
schemaVersionsCount={project.schemaVersionsCount}
/>
))}
{projects.map(project => (
<ProjectCard
key={project.id}
cleanOrganizationId={currentOrganization.cleanId}
days={days}
highestNumberOfRequests={highestNumberOfRequests}
project={project}
requestsOverTime={project.requestsOverTime}
schemaVersionsCount={project.schemaVersionsCount}
/>
))}
</div>
)
) : (
@ -357,11 +493,20 @@ function OrganizationPageContent(props: { organizationId: string }) {
);
}
export function OrganizationPage(props: { organizationId: string }): ReactElement {
export function OrganizationPage(
props: {
organizationId: string;
} & RouteSearchProps,
) {
return (
<>
<Meta title="Organization" />
<OrganizationPageContent organizationId={props.organizationId} />
<OrganizationPageContent
organizationId={props.organizationId}
search={props.search}
sortBy={props.sortBy}
sortOrder={props.sortOrder}
/>
</>
);
}

View file

@ -2,14 +2,19 @@ import { ReactElement, useMemo, useRef } from 'react';
import { endOfDay, formatISO, startOfDay } from 'date-fns';
import * as echarts from 'echarts';
import ReactECharts from 'echarts-for-react';
import { Globe, History } from 'lucide-react';
import { Globe, History, MoveDownIcon, MoveUpIcon, SearchIcon } from 'lucide-react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { useQuery } from 'urql';
import { z } from 'zod';
import { Page, ProjectLayout } from '@/components/layouts/project';
import { Button } from '@/components/ui/button';
import { EmptyList } from '@/components/ui/empty-list';
import { Input } from '@/components/ui/input';
import { Meta } from '@/components/ui/meta';
import { Subtitle, Title } from '@/components/ui/page';
import { QueryError } from '@/components/ui/query-error';
import { Select, SelectContent, SelectItem, SelectTrigger } from '@/components/ui/select';
import { Separator } from '@/components/ui/separator';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
import { Card } from '@/components/v2/card';
import { FragmentType, graphql, useFragment } from '@/gql';
@ -17,7 +22,7 @@ import { subDays } from '@/lib/date-time';
import { useFormattedNumber } from '@/lib/hooks';
import { cn, pluralize } from '@/lib/utils';
import { UTCDate } from '@date-fns/utc';
import { Link } from '@tanstack/react-router';
import { Link, useRouter } from '@tanstack/react-router';
const TargetCard_TargetFragment = graphql(`
fragment TargetCard_TargetFragment on Target {
@ -201,7 +206,17 @@ const TargetCard = (props: {
);
};
const ProjectsPageContent = (props: { organizationId: string; projectId: string }) => {
export const ProjectIndexRouteSearch = z.object({
search: z.string().optional(),
sortBy: z.enum(['requests', 'versions', 'name']).optional(),
sortOrder: z.enum(['asc', 'desc']).optional(),
});
type RouteSearchProps = z.infer<typeof ProjectIndexRouteSearch>;
const ProjectsPageContent = (
props: { organizationId: string; projectId: string } & RouteSearchProps,
) => {
const period = useRef<{
from: string;
to: string;
@ -216,6 +231,19 @@ const ProjectsPageContent = (props: { organizationId: string; projectId: string
period.current = { from, to };
}
// Sort by requests by default
const sortKey = props.sortBy ?? 'requests';
const sortOrder =
props.sortOrder === 'asc'
? -1
: // if the sort order is not set, sort by name in ascending order by default
!props.sortOrder && props.sortBy === 'name'
? -1
: // if the sort order is not set, sort in descending order by default
1;
const router = useRouter();
const [query] = useQuery({
query: ProjectOverviewPageQuery,
variables: {
@ -228,11 +256,43 @@ const ProjectsPageContent = (props: { organizationId: string; projectId: string
});
const targetConnection = query.data?.targets;
const targets = targetConnection?.nodes;
const targets = useMemo(() => {
if (!targetConnection) {
return [];
}
const searchPhrase = props.search;
const newTargets = searchPhrase
? targetConnection.nodes.filter(target =>
target.name.toLowerCase().includes(searchPhrase.toLowerCase()),
)
: targetConnection.nodes.slice();
return newTargets.sort((a, b) => {
const diffRequests = b.totalRequests - a.totalRequests;
const diffVersions = b.schemaVersionsCount - a.schemaVersionsCount;
if (sortKey === 'requests' && diffRequests !== 0) {
return diffRequests * sortOrder;
}
if (sortKey === 'versions' && diffVersions !== 0) {
return diffVersions * sortOrder;
}
if (sortKey === 'name') {
return a.name.localeCompare(b.name) * sortOrder * -1;
}
// falls back to sort by name in ascending order
return a.name.localeCompare(b.name);
});
}, [targetConnection, props.search, sortKey, sortOrder]);
const highestNumberOfRequests = useMemo(() => {
if (targets?.length) {
return targets.reduce((max, target) => {
if (targetConnection?.nodes?.length) {
return targetConnection.nodes.reduce((max, target) => {
return Math.max(
max,
target.requestsOverTime.reduce((max, { value }) => Math.max(max, value), 0),
@ -241,7 +301,7 @@ const ProjectsPageContent = (props: { organizationId: string; projectId: string
}
return 100;
}, [targets]);
}, [targetConnection?.nodes]);
if (query.error) {
return <QueryError organizationId={props.organizationId} error={query.error} />;
@ -255,50 +315,124 @@ const ProjectsPageContent = (props: { organizationId: string; projectId: string
className="flex justify-between gap-12"
>
<div className="grow">
<div className="py-6">
<Title>Targets</Title>
<Subtitle>A list of available targets in your project.</Subtitle>
<div className="flex flex-row items-center justify-between py-6">
<div>
<Title>Targets</Title>
<Subtitle>A list of available targets in your project.</Subtitle>
</div>
<div>
<div className="flex flex-row items-center gap-x-2">
<div className="relative">
<SearchIcon className="text-muted-foreground absolute left-2.5 top-2.5 size-4" />
<Input
type="search"
placeholder="Search..."
value={props.search}
onChange={event => {
void router.navigate({
search(params) {
return {
...params,
search: event.target.value,
};
},
});
}}
className="bg-background w-full rounded-lg pl-8 md:w-[200px] lg:w-[336px]"
/>
</div>
<Separator orientation="vertical" className="mx-4 h-8" />
<Select
value={props.sortBy ?? 'requests'}
onValueChange={value => {
void router.navigate({
search(params) {
return {
...params,
sortBy: value,
};
},
});
}}
>
<SelectTrigger className="hover:bg-accent bg-transparent">
{props.sortBy === 'versions'
? 'Schema Versions'
: props.sortBy === 'name'
? 'Name'
: 'Requests'}
</SelectTrigger>
<SelectContent>
<SelectItem value="requests">
<div className="font-bold">Requests</div>
<div className="text-muted-foreground text-xs">
GraphQL requests made in the last {days} days.
</div>
</SelectItem>
<SelectItem value="versions">
<div className="font-bold">Schema Versions</div>
<div className="text-muted-foreground text-xs">
Schemas published in last {days} days.
</div>
</SelectItem>
<SelectItem value="name">
<div className="font-bold">Name</div>
<div className="text-muted-foreground text-xs">Sort by target name.</div>
</SelectItem>
</SelectContent>
</Select>
<Button
className="shrink-0"
variant="outline"
size="icon"
onClick={() => {
void router.navigate({
search(params) {
return {
...params,
sortOrder: props.sortOrder === 'asc' ? 'desc' : 'asc',
};
},
});
}}
>
{props.sortOrder === 'asc' ? (
<MoveUpIcon className="size-4" />
) : (
<MoveDownIcon className="size-4" />
)}
</Button>
</div>
</div>
</div>
<div
className={cn(
'grow',
targets?.length === 0 ? '' : 'grid grid-cols-2 items-stretch gap-5 xl:grid-cols-3',
targetConnection?.total === 0
? ''
: 'grid grid-cols-2 items-stretch gap-5 xl:grid-cols-3',
)}
>
{targets ? (
targets.length === 0 ? (
{targetConnection ? (
targetConnection?.total === 0 ? (
<EmptyList
title="Hive is waiting for your first target"
description='You can create a target by clicking the "New Target" button'
docsUrl="/management/targets#create-a-new-target"
/>
) : (
targets
.sort((a, b) => {
const diffOperations = b.totalRequests - a.totalRequests;
if (diffOperations !== 0) {
return diffOperations;
}
const diffVersions = b.schemaVersionsCount - a.schemaVersionsCount;
if (diffVersions !== 0) {
return diffVersions;
}
return a.name.localeCompare(b.name);
})
.map(target => (
<TargetCard
key={target.id}
target={target}
days={days}
highestNumberOfRequests={highestNumberOfRequests}
requestsOverTime={target.requestsOverTime}
schemaVersionsCount={target.schemaVersionsCount}
organizationId={props.organizationId}
projectId={props.projectId}
/>
))
targets.map(target => (
<TargetCard
key={target.id}
target={target}
days={days}
highestNumberOfRequests={highestNumberOfRequests}
requestsOverTime={target.requestsOverTime}
schemaVersionsCount={target.schemaVersionsCount}
organizationId={props.organizationId}
projectId={props.projectId}
/>
))
)
) : (
<>
@ -346,11 +480,19 @@ const ProjectOverviewPageQuery = graphql(`
}
`);
export function ProjectPage(props: { organizationId: string; projectId: string }): ReactElement {
export function ProjectPage(
props: { organizationId: string; projectId: string } & RouteSearchProps,
): ReactElement {
return (
<>
<Meta title="Targets" />
<ProjectsPageContent organizationId={props.organizationId} projectId={props.projectId} />
<ProjectsPageContent
organizationId={props.organizationId}
projectId={props.projectId}
search={props.search}
sortBy={props.sortBy}
sortOrder={props.sortOrder}
/>
</>
);
}

View file

@ -37,7 +37,7 @@ import { DevPage } from './pages/dev';
import { IndexPage } from './pages/index';
import { LogoutPage } from './pages/logout';
import { ManagePage } from './pages/manage';
import { OrganizationPage } from './pages/organization';
import { OrganizationIndexRouteSearch, OrganizationPage } from './pages/organization';
import { JoinOrganizationPage } from './pages/organization-join';
import { OrganizationMembersPage } from './pages/organization-members';
import { NewOrgPage } from './pages/organization-new';
@ -48,7 +48,7 @@ import { OrganizationSubscriptionManagePage } from './pages/organization-subscri
import { OrganizationSupportPage } from './pages/organization-support';
import { OrganizationSupportTicketPage } from './pages/organization-support-ticket';
import { OrganizationTransferPage } from './pages/organization-transfer';
import { ProjectPage } from './pages/project';
import { ProjectIndexRouteSearch, ProjectPage } from './pages/project';
import { ProjectAlertsPage } from './pages/project-alerts';
import { ProjectPolicyPage } from './pages/project-policy';
import { ProjectSettingsPage } from './pages/project-settings';
@ -345,9 +345,18 @@ const organizationRoute = createRoute({
const organizationIndexRoute = createRoute({
getParentRoute: () => organizationRoute,
path: '/',
validateSearch: OrganizationIndexRouteSearch.parse,
component: function OrganizationRoute() {
const { organizationId } = organizationRoute.useParams();
return <OrganizationPage organizationId={organizationId} />;
const { search, sortBy, sortOrder } = organizationIndexRoute.useSearch();
return (
<OrganizationPage
organizationId={organizationId}
search={search}
sortBy={sortBy}
sortOrder={sortOrder}
/>
);
},
notFoundComponent: NotFound,
errorComponent: ErrorComponent,
@ -457,9 +466,19 @@ const projectRoute = createRoute({
const projectIndexRoute = createRoute({
getParentRoute: () => projectRoute,
path: '/',
validateSearch: ProjectIndexRouteSearch.parse,
component: function ProjectRoute() {
const { organizationId, projectId } = projectIndexRoute.useParams();
return <ProjectPage organizationId={organizationId} projectId={projectId} />;
const { search, sortBy, sortOrder } = projectIndexRoute.useSearch();
return (
<ProjectPage
organizationId={organizationId}
projectId={projectId}
search={search}
sortBy={sortBy}
sortOrder={sortOrder}
/>
);
},
});

View file

@ -16968,10 +16968,10 @@ snapshots:
dependencies:
'@aws-crypto/sha256-browser': 3.0.0
'@aws-crypto/sha256-js': 3.0.0
'@aws-sdk/client-sso-oidc': 3.596.0
'@aws-sdk/client-sts': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)
'@aws-sdk/client-sso-oidc': 3.596.0(@aws-sdk/client-sts@3.596.0)
'@aws-sdk/client-sts': 3.596.0
'@aws-sdk/core': 3.592.0
'@aws-sdk/credential-provider-node': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)(@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0))
'@aws-sdk/credential-provider-node': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0))(@aws-sdk/client-sts@3.596.0)
'@aws-sdk/middleware-host-header': 3.577.0
'@aws-sdk/middleware-logger': 3.577.0
'@aws-sdk/middleware-recursion-detection': 3.577.0
@ -17076,13 +17076,13 @@ snapshots:
transitivePeerDependencies:
- aws-crt
'@aws-sdk/client-sso-oidc@3.596.0':
'@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0)':
dependencies:
'@aws-crypto/sha256-browser': 3.0.0
'@aws-crypto/sha256-js': 3.0.0
'@aws-sdk/client-sts': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)
'@aws-sdk/client-sts': 3.596.0
'@aws-sdk/core': 3.592.0
'@aws-sdk/credential-provider-node': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)(@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0))
'@aws-sdk/credential-provider-node': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0))(@aws-sdk/client-sts@3.596.0)
'@aws-sdk/middleware-host-header': 3.577.0
'@aws-sdk/middleware-logger': 3.577.0
'@aws-sdk/middleware-recursion-detection': 3.577.0
@ -17119,6 +17119,7 @@ snapshots:
'@smithy/util-utf8': 3.0.0
tslib: 2.6.3
transitivePeerDependencies:
- '@aws-sdk/client-sts'
- aws-crt
'@aws-sdk/client-sso-oidc@3.614.0(@aws-sdk/client-sts@3.614.0)':
@ -17252,13 +17253,13 @@ snapshots:
transitivePeerDependencies:
- aws-crt
'@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0)':
'@aws-sdk/client-sts@3.596.0':
dependencies:
'@aws-crypto/sha256-browser': 3.0.0
'@aws-crypto/sha256-js': 3.0.0
'@aws-sdk/client-sso-oidc': 3.596.0
'@aws-sdk/client-sso-oidc': 3.596.0(@aws-sdk/client-sts@3.596.0)
'@aws-sdk/core': 3.592.0
'@aws-sdk/credential-provider-node': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)(@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0))
'@aws-sdk/credential-provider-node': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0))(@aws-sdk/client-sts@3.596.0)
'@aws-sdk/middleware-host-header': 3.577.0
'@aws-sdk/middleware-logger': 3.577.0
'@aws-sdk/middleware-recursion-detection': 3.577.0
@ -17295,7 +17296,6 @@ snapshots:
'@smithy/util-utf8': 3.0.0
tslib: 2.6.3
transitivePeerDependencies:
- '@aws-sdk/client-sso-oidc'
- aws-crt
'@aws-sdk/client-sts@3.614.0':
@ -17401,14 +17401,14 @@ snapshots:
'@smithy/util-stream': 3.0.6
tslib: 2.6.3
'@aws-sdk/credential-provider-ini@3.596.0(@aws-sdk/client-sso-oidc@3.596.0)(@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0))':
'@aws-sdk/credential-provider-ini@3.596.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0))(@aws-sdk/client-sts@3.596.0)':
dependencies:
'@aws-sdk/client-sts': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)
'@aws-sdk/client-sts': 3.596.0
'@aws-sdk/credential-provider-env': 3.587.0
'@aws-sdk/credential-provider-http': 3.596.0
'@aws-sdk/credential-provider-process': 3.587.0
'@aws-sdk/credential-provider-sso': 3.592.0(@aws-sdk/client-sso-oidc@3.596.0)
'@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0))
'@aws-sdk/credential-provider-sso': 3.592.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0))
'@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.596.0)
'@aws-sdk/types': 3.577.0
'@smithy/credential-provider-imds': 3.1.3
'@smithy/property-provider': 3.1.3
@ -17437,14 +17437,14 @@ snapshots:
- '@aws-sdk/client-sso-oidc'
- aws-crt
'@aws-sdk/credential-provider-node@3.596.0(@aws-sdk/client-sso-oidc@3.596.0)(@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0))':
'@aws-sdk/credential-provider-node@3.596.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0))(@aws-sdk/client-sts@3.596.0)':
dependencies:
'@aws-sdk/credential-provider-env': 3.587.0
'@aws-sdk/credential-provider-http': 3.596.0
'@aws-sdk/credential-provider-ini': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)(@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0))
'@aws-sdk/credential-provider-ini': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0))(@aws-sdk/client-sts@3.596.0)
'@aws-sdk/credential-provider-process': 3.587.0
'@aws-sdk/credential-provider-sso': 3.592.0(@aws-sdk/client-sso-oidc@3.596.0)
'@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0))
'@aws-sdk/credential-provider-sso': 3.592.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0))
'@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.596.0)
'@aws-sdk/types': 3.577.0
'@smithy/credential-provider-imds': 3.1.3
'@smithy/property-provider': 3.1.3
@ -17491,10 +17491,10 @@ snapshots:
'@smithy/types': 3.3.0
tslib: 2.6.3
'@aws-sdk/credential-provider-sso@3.592.0(@aws-sdk/client-sso-oidc@3.596.0)':
'@aws-sdk/credential-provider-sso@3.592.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0))':
dependencies:
'@aws-sdk/client-sso': 3.592.0
'@aws-sdk/token-providers': 3.587.0(@aws-sdk/client-sso-oidc@3.596.0)
'@aws-sdk/token-providers': 3.587.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0))
'@aws-sdk/types': 3.577.0
'@smithy/property-provider': 3.1.3
'@smithy/shared-ini-file-loader': 3.1.3
@ -17517,9 +17517,9 @@ snapshots:
- '@aws-sdk/client-sso-oidc'
- aws-crt
'@aws-sdk/credential-provider-web-identity@3.587.0(@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0))':
'@aws-sdk/credential-provider-web-identity@3.587.0(@aws-sdk/client-sts@3.596.0)':
dependencies:
'@aws-sdk/client-sts': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)
'@aws-sdk/client-sts': 3.596.0
'@aws-sdk/types': 3.577.0
'@smithy/property-provider': 3.1.3
'@smithy/types': 3.3.0
@ -17689,9 +17689,9 @@ snapshots:
'@smithy/types': 3.3.0
tslib: 2.6.3
'@aws-sdk/token-providers@3.587.0(@aws-sdk/client-sso-oidc@3.596.0)':
'@aws-sdk/token-providers@3.587.0(@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0))':
dependencies:
'@aws-sdk/client-sso-oidc': 3.596.0
'@aws-sdk/client-sso-oidc': 3.596.0(@aws-sdk/client-sts@3.596.0)
'@aws-sdk/types': 3.577.0
'@smithy/property-provider': 3.1.3
'@smithy/shared-ini-file-loader': 3.1.3