diff --git a/assets/src/components/cd/services/TagSelection.tsx b/assets/src/components/cd/services/TagSelection.tsx index 1169468070..9845dbdb91 100644 --- a/assets/src/components/cd/services/TagSelection.tsx +++ b/assets/src/components/cd/services/TagSelection.tsx @@ -83,7 +83,7 @@ export function TagSelection({ css={{ '&&': { flexGrow: 0 } }} type="secondary" tooltip={tagIsValid ? 'Add tag' : 'Tag is incomplete or invalid'} - size="medium" + size="large" clickable={tagIsValid} icon={ navigate(EDGE_ABS_PATH), + deps: [navigate], + hotkeys: ['shift E'], + }, { label: 'Service catalog', icon: CatalogIcon, diff --git a/assets/src/components/edge/CompleteClusterRegistrationModal.tsx b/assets/src/components/edge/CompleteClusterRegistrationModal.tsx new file mode 100644 index 0000000000..f6df893ecd --- /dev/null +++ b/assets/src/components/edge/CompleteClusterRegistrationModal.tsx @@ -0,0 +1,130 @@ +import { Button, FormField, Modal, Input } from '@pluralsh/design-system' +import { ComponentProps, useState } from 'react' +import { useTheme } from 'styled-components' +import { useUpdateClusterRegistrationMutation } from 'generated/graphql' +import { ModalMountTransition } from 'components/utils/ModalMountTransition' +import { GqlError } from '../utils/Alert.tsx' +import { TagSelection } from '../cd/services/TagSelection.tsx' +import { tagsToNameValue } from '../cd/services/CreateGlobalService.tsx' +function CompleteClusterRegistrationModal({ + id, + machineId, + open, + onClose, + refetch, +}: { + id: string + machineId: string + open: boolean + onClose: () => void + refetch?: () => void +}) { + const theme = useTheme() + const [name, setName] = useState('') + const [handle, setHandle] = useState('') + const [tags, setTags] = useState>({}) + + const [mutation, { loading, error }] = useUpdateClusterRegistrationMutation({ + onCompleted: () => { + onClose() + refetch?.() + }, + }) + + return ( + e.preventDefault()} + asForm + onSubmit={(e) => { + e.preventDefault() + mutation({ + variables: { + id: id, + attributes: { + name, + handle, + tags: tagsToNameValue(tags), + }, + }, + }) + }} + size="large" + open={open} + onClose={onClose} + header={`Complete cluster registration`} + actions={ +
+ + +
+ } + > +
+

+ Provide cluster details to complete registration on machine with{' '} + {machineId} ID. +

+ {error && } + + setName(e.target.value)} + /> + + + setHandle(e.target.value)} + /> + + + + +
+
+ ) +} + +export function CreateCompleteClusterRegistrationModal( + props: ComponentProps +) { + return ( + + + + ) +} diff --git a/assets/src/components/edge/Edge.tsx b/assets/src/components/edge/Edge.tsx new file mode 100644 index 0000000000..2792a56fe3 --- /dev/null +++ b/assets/src/components/edge/Edge.tsx @@ -0,0 +1,202 @@ +import { ResponsivePageFullWidth } from 'components/utils/layout/ResponsivePageFullWidth' +import { useTheme } from 'styled-components' +import { + AppIcon, + Button, + ChipList, + LoopingLogo, + Table, + useSetBreadcrumbs, +} from '@pluralsh/design-system' +import { + DEFAULT_REACT_VIRTUAL_OPTIONS, + useFetchPaginatedData, +} from '../utils/table/useFetchPaginatedData.tsx' +import { FullHeightTableWrap } from '../utils/layout/FullHeightTableWrap.tsx' +import { + ClusterRegistrationFragment, + useClusterRegistrationsQuery, +} from '../../generated/graphql.ts' +import { useMemo, useState } from 'react' +import { mapExistingNodes } from '../../utils/graphql.ts' +import { createColumnHelper } from '@tanstack/react-table' +import { DateTimeCol } from '../utils/table/DateTimeCol.tsx' +import { GqlError } from '../utils/Alert.tsx' + +import { EDGE_BASE_CRUMBS } from '../../routes/edgeRoutes.tsx' +import { Flex } from 'honorable' +import { StackedText } from '../utils/table/StackedText.tsx' +import { CreateCompleteClusterRegistrationModal } from './CompleteClusterRegistrationModal.tsx' + +const renderTag = (tag) => `${tag.name}${tag.value ? `: ${tag.value}` : ''}` + +export const columnHelper = createColumnHelper() + +const columns = [ + columnHelper.accessor((registration) => registration.machineId, { + id: 'machineId', + header: 'Machine ID', + meta: { truncate: true, gridTemplate: 'minmax(150px,1fr)' }, + cell: ({ getValue }) => getValue(), + }), + columnHelper.accessor((registration) => registration.project?.name, { + id: 'project', + header: 'Project', + meta: { truncate: true, gridTemplate: 'minmax(150px,1fr)' }, + }), + columnHelper.accessor(() => null, { + id: 'cluster', + header: 'Cluster', + meta: { truncate: true, gridTemplate: 'minmax(150px,1fr)' }, + cell: ({ + row: { + original: { name, handle }, + }, + }) => ( + + ), + }), + columnHelper.accessor((registration) => registration.tags ?? [], { + id: 'tags', + header: 'Tags', + cell: ({ getValue }) => ( + + ), + }), + columnHelper.accessor((registration) => registration.creator, { + id: 'creator', + header: 'Creator', + meta: { truncate: true, gridTemplate: 'minmax(150px,1fr)' }, + cell: ({ getValue }) => { + const creator = getValue() + + return ( + + {(creator?.profile || creator?.name) && ( + + )} + {creator?.email} + + ) + }, + }), + columnHelper.accessor((registration) => registration.insertedAt, { + id: 'insertedAt', + header: 'Created', + enableSorting: true, + enableGlobalFilter: true, + cell: ({ getValue }) => , + }), + columnHelper.accessor(() => null, { + id: 'actions', + header: '', + meta: { gridTemplate: `fit-content(100px)` }, + cell: function Cell({ + row: { + original: { id, machineId, name }, + }, + table, + }) { + const { refetch } = table.options.meta as { refetch?: () => void } + const [open, setOpen] = useState(false) + + return ( + <> + {!name && ( + + )} + setOpen(false)} + refetch={refetch} + /> + + ) + }, + }), +] + +export default function Edge() { + const theme = useTheme() + + useSetBreadcrumbs(EDGE_BASE_CRUMBS) + + const { + data, + loading, + error, + refetch, + pageInfo, + fetchNextPage, + setVirtualSlice, + } = useFetchPaginatedData({ + queryHook: useClusterRegistrationsQuery, + keyPath: ['clusterRegistrations'], + }) + + const clusterRegistrations = useMemo( + () => mapExistingNodes(data?.clusterRegistrations), + [data?.clusterRegistrations] + ) + + if (error) return + + if (!data) return + + return ( + + Edge cluster registrations + + } + > + + + + + ) +} diff --git a/assets/src/components/layout/Sidebar.tsx b/assets/src/components/layout/Sidebar.tsx index 318cfad73a..6ab4b7ac6c 100644 --- a/assets/src/components/layout/Sidebar.tsx +++ b/assets/src/components/layout/Sidebar.tsx @@ -24,6 +24,7 @@ import { StackIcon, Tooltip, WarningShieldIcon, + RamIcon, } from '@pluralsh/design-system' import { ME_Q } from 'components/graphql/users' import { Avatar, Flex, Menu, MenuItem } from 'honorable' @@ -53,6 +54,7 @@ import { CATALOGS_ABS_PATH } from '../../routes/catalogRoutesConsts.tsx' import CommandPaletteShortcuts from '../commandpalette/CommandPaletteShortcuts.tsx' import { NotificationsPanelOverlay } from './NotificationsPanelOverlay' import { MARK_READ } from './queries' +import { EDGE_ABS_PATH } from '../../routes/edgeRoutes.tsx' type MenuItem = { text: string @@ -122,6 +124,13 @@ function getMenuItems({ path: `${AI_ABS_PATH}`, hotkeys: ['shift A', '6'], }, + { + text: 'Edge', + expandedLabel: 'Edge', + icon: , + path: EDGE_ABS_PATH, + hotkeys: ['shift E'], + }, { text: 'PRs', expandedLabel: 'Pull requests', diff --git a/assets/src/generated/graphql-kubernetes.ts b/assets/src/generated/graphql-kubernetes.ts index d29b0e2876..d1042cfb91 100644 --- a/assets/src/generated/graphql-kubernetes.ts +++ b/assets/src/generated/graphql-kubernetes.ts @@ -1,4 +1,4 @@ - +/* eslint-disable */ /* prettier-ignore */ import { gql } from '@apollo/client'; import * as Apollo from '@apollo/client'; diff --git a/assets/src/generated/graphql-plural.ts b/assets/src/generated/graphql-plural.ts index 2a8b931afc..694f1a631a 100644 --- a/assets/src/generated/graphql-plural.ts +++ b/assets/src/generated/graphql-plural.ts @@ -1,4 +1,4 @@ - +/* eslint-disable */ /* prettier-ignore */ import { gql } from '@apollo/client'; import * as Apollo from '@apollo/client'; diff --git a/assets/src/generated/graphql.ts b/assets/src/generated/graphql.ts index 9ed87b60cd..0a4239972b 100644 --- a/assets/src/generated/graphql.ts +++ b/assets/src/generated/graphql.ts @@ -1,4 +1,4 @@ - +/* eslint-disable */ /* prettier-ignore */ import { gql } from '@apollo/client'; import * as Apollo from '@apollo/client'; @@ -10747,6 +10747,50 @@ export type ApplyScalingRecommendationMutationVariables = Exact<{ export type ApplyScalingRecommendationMutation = { __typename?: 'RootMutationType', applyScalingRecommendation?: { __typename?: 'PullRequest', id: string, title?: string | null, url: string, labels?: Array | null, creator?: string | null, status?: PrStatus | null, insertedAt?: string | null, updatedAt?: string | null, service?: { __typename?: 'ServiceDeployment', id: string, name: string, protect?: boolean | null, deletedAt?: string | null } | null, cluster?: { __typename?: 'Cluster', protect?: boolean | null, deletedAt?: string | null, version?: string | null, currentVersion?: string | null, self?: boolean | null, virtual?: boolean | null, id: string, name: string, handle?: string | null, distro?: ClusterDistro | null, upgradePlan?: { __typename?: 'ClusterUpgradePlan', compatibilities?: boolean | null, deprecations?: boolean | null, incompatibilities?: boolean | null } | null, provider?: { __typename?: 'ClusterProvider', cloud: string } | null } | null } | null }; +export type ClusterRegistrationFragment = { __typename?: 'ClusterRegistration', id: string, insertedAt?: string | null, updatedAt?: string | null, machineId: string, name?: string | null, handle?: string | null, metadata?: Record | null, tags?: Array<{ __typename?: 'Tag', name: string, value: string } | null> | null, creator?: { __typename?: 'User', name: string, email: string, profile?: string | null } | null, project?: { __typename?: 'Project', id: string, name: string, default?: boolean | null, description?: string | null } | null }; + +export type TagFragment = { __typename?: 'Tag', name: string, value: string }; + +export type ClusterRegistrationQueryVariables = Exact<{ + id?: InputMaybe; + machineId?: InputMaybe; +}>; + + +export type ClusterRegistrationQuery = { __typename?: 'RootQueryType', clusterRegistration?: { __typename?: 'ClusterRegistration', id: string, insertedAt?: string | null, updatedAt?: string | null, machineId: string, name?: string | null, handle?: string | null, metadata?: Record | null, tags?: Array<{ __typename?: 'Tag', name: string, value: string } | null> | null, creator?: { __typename?: 'User', name: string, email: string, profile?: string | null } | null, project?: { __typename?: 'Project', id: string, name: string, default?: boolean | null, description?: string | null } | null } | null }; + +export type ClusterRegistrationsQueryVariables = Exact<{ + after?: InputMaybe; + first?: InputMaybe; + before?: InputMaybe; + last?: InputMaybe; +}>; + + +export type ClusterRegistrationsQuery = { __typename?: 'RootQueryType', clusterRegistrations?: { __typename?: 'ClusterRegistrationConnection', pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean, endCursor?: string | null, hasPreviousPage: boolean, startCursor?: string | null }, edges?: Array<{ __typename?: 'ClusterRegistrationEdge', node?: { __typename?: 'ClusterRegistration', id: string, insertedAt?: string | null, updatedAt?: string | null, machineId: string, name?: string | null, handle?: string | null, metadata?: Record | null, tags?: Array<{ __typename?: 'Tag', name: string, value: string } | null> | null, creator?: { __typename?: 'User', name: string, email: string, profile?: string | null } | null, project?: { __typename?: 'Project', id: string, name: string, default?: boolean | null, description?: string | null } | null } | null } | null> | null } | null }; + +export type CreateClusterRegistrationMutationVariables = Exact<{ + attributes: ClusterRegistrationCreateAttributes; +}>; + + +export type CreateClusterRegistrationMutation = { __typename?: 'RootMutationType', createClusterRegistration?: { __typename?: 'ClusterRegistration', id: string, insertedAt?: string | null, updatedAt?: string | null, machineId: string, name?: string | null, handle?: string | null, metadata?: Record | null, tags?: Array<{ __typename?: 'Tag', name: string, value: string } | null> | null, creator?: { __typename?: 'User', name: string, email: string, profile?: string | null } | null, project?: { __typename?: 'Project', id: string, name: string, default?: boolean | null, description?: string | null } | null } | null }; + +export type UpdateClusterRegistrationMutationVariables = Exact<{ + id: Scalars['ID']['input']; + attributes: ClusterRegistrationUpdateAttributes; +}>; + + +export type UpdateClusterRegistrationMutation = { __typename?: 'RootMutationType', updateClusterRegistration?: { __typename?: 'ClusterRegistration', id: string, insertedAt?: string | null, updatedAt?: string | null, machineId: string, name?: string | null, handle?: string | null, metadata?: Record | null, tags?: Array<{ __typename?: 'Tag', name: string, value: string } | null> | null, creator?: { __typename?: 'User', name: string, email: string, profile?: string | null } | null, project?: { __typename?: 'Project', id: string, name: string, default?: boolean | null, description?: string | null } | null } | null }; + +export type DeleteClusterRegistrationMutationVariables = Exact<{ + id: Scalars['ID']['input']; +}>; + + +export type DeleteClusterRegistrationMutation = { __typename?: 'RootMutationType', deleteClusterRegistration?: { __typename?: 'ClusterRegistration', id: string, insertedAt?: string | null, updatedAt?: string | null, machineId: string, name?: string | null, handle?: string | null, metadata?: Record | null, tags?: Array<{ __typename?: 'Tag', name: string, value: string } | null> | null, creator?: { __typename?: 'User', name: string, email: string, profile?: string | null } | null, project?: { __typename?: 'Project', id: string, name: string, default?: boolean | null, description?: string | null } | null } | null }; + export type GroupMemberFragment = { __typename?: 'GroupMember', user?: { __typename?: 'User', id: string, pluralId?: string | null, name: string, email: string, profile?: string | null, backgroundColor?: string | null, readTimestamp?: string | null, emailSettings?: { __typename?: 'EmailSettings', digest?: boolean | null } | null, roles?: { __typename?: 'UserRoles', admin?: boolean | null } | null, personas?: Array<{ __typename?: 'Persona', id: string, name: string, description?: string | null, bindings?: Array<{ __typename?: 'PolicyBinding', id?: string | null, user?: { __typename?: 'User', id: string, name: string, email: string } | null, group?: { __typename?: 'Group', id: string, name: string } | null } | null> | null, configuration?: { __typename?: 'PersonaConfiguration', all?: boolean | null, deployments?: { __typename?: 'PersonaDeployment', addOns?: boolean | null, clusters?: boolean | null, pipelines?: boolean | null, providers?: boolean | null, repositories?: boolean | null, services?: boolean | null } | null, home?: { __typename?: 'PersonaHome', manager?: boolean | null, security?: boolean | null } | null, sidebar?: { __typename?: 'PersonaSidebar', audits?: boolean | null, kubernetes?: boolean | null, pullRequests?: boolean | null, settings?: boolean | null, backups?: boolean | null, stacks?: boolean | null } | null } | null } | null> | null } | null, group?: { __typename?: 'Group', id: string, name: string, description?: string | null, global?: boolean | null, insertedAt?: string | null, updatedAt?: string | null } | null }; export type GroupFragment = { __typename?: 'Group', id: string, name: string, description?: string | null, global?: boolean | null, insertedAt?: string | null, updatedAt?: string | null }; @@ -11613,6 +11657,8 @@ export type ConsumeSecretMutation = { __typename?: 'RootMutationType', consumeSe export type UserFragment = { __typename?: 'User', id: string, pluralId?: string | null, name: string, email: string, profile?: string | null, backgroundColor?: string | null, readTimestamp?: string | null, emailSettings?: { __typename?: 'EmailSettings', digest?: boolean | null } | null, roles?: { __typename?: 'UserRoles', admin?: boolean | null } | null, personas?: Array<{ __typename?: 'Persona', id: string, name: string, description?: string | null, bindings?: Array<{ __typename?: 'PolicyBinding', id?: string | null, user?: { __typename?: 'User', id: string, name: string, email: string } | null, group?: { __typename?: 'Group', id: string, name: string } | null } | null> | null, configuration?: { __typename?: 'PersonaConfiguration', all?: boolean | null, deployments?: { __typename?: 'PersonaDeployment', addOns?: boolean | null, clusters?: boolean | null, pipelines?: boolean | null, providers?: boolean | null, repositories?: boolean | null, services?: boolean | null } | null, home?: { __typename?: 'PersonaHome', manager?: boolean | null, security?: boolean | null } | null, sidebar?: { __typename?: 'PersonaSidebar', audits?: boolean | null, kubernetes?: boolean | null, pullRequests?: boolean | null, settings?: boolean | null, backups?: boolean | null, stacks?: boolean | null } | null } | null } | null> | null }; +export type UserTinyFragment = { __typename?: 'User', name: string, email: string, profile?: string | null }; + export type InviteFragment = { __typename?: 'Invite', secureId: string }; export type RoleBindingFragment = { __typename?: 'RoleBinding', id: string, user?: { __typename?: 'User', id: string, pluralId?: string | null, name: string, email: string, profile?: string | null, backgroundColor?: string | null, readTimestamp?: string | null, emailSettings?: { __typename?: 'EmailSettings', digest?: boolean | null } | null, roles?: { __typename?: 'UserRoles', admin?: boolean | null } | null, personas?: Array<{ __typename?: 'Persona', id: string, name: string, description?: string | null, bindings?: Array<{ __typename?: 'PolicyBinding', id?: string | null, user?: { __typename?: 'User', id: string, name: string, email: string } | null, group?: { __typename?: 'Group', id: string, name: string } | null } | null> | null, configuration?: { __typename?: 'PersonaConfiguration', all?: boolean | null, deployments?: { __typename?: 'PersonaDeployment', addOns?: boolean | null, clusters?: boolean | null, pipelines?: boolean | null, providers?: boolean | null, repositories?: boolean | null, services?: boolean | null } | null, home?: { __typename?: 'PersonaHome', manager?: boolean | null, security?: boolean | null } | null, sidebar?: { __typename?: 'PersonaSidebar', audits?: boolean | null, kubernetes?: boolean | null, pullRequests?: boolean | null, settings?: boolean | null, backups?: boolean | null, stacks?: boolean | null } | null } | null } | null> | null } | null, group?: { __typename?: 'Group', id: string, name: string, description?: string | null, global?: boolean | null, insertedAt?: string | null, updatedAt?: string | null } | null }; @@ -13523,6 +13569,41 @@ export const ClusterScalingRecommendationFragmentDoc = gql` } } ${ServiceDeploymentTinyFragmentDoc}`; +export const TagFragmentDoc = gql` + fragment Tag on Tag { + name + value +} + `; +export const UserTinyFragmentDoc = gql` + fragment UserTiny on User { + name + email + profile +} + `; +export const ClusterRegistrationFragmentDoc = gql` + fragment ClusterRegistration on ClusterRegistration { + id + insertedAt + updatedAt + machineId + name + handle + metadata + tags { + ...Tag + } + creator { + ...UserTiny + } + project { + ...ProjectTiny + } +} + ${TagFragmentDoc} +${UserTinyFragmentDoc} +${ProjectTinyFragmentDoc}`; export const GroupFragmentDoc = gql` fragment Group on Group { id @@ -20855,6 +20936,198 @@ export function useApplyScalingRecommendationMutation(baseOptions?: Apollo.Mutat export type ApplyScalingRecommendationMutationHookResult = ReturnType; export type ApplyScalingRecommendationMutationResult = Apollo.MutationResult; export type ApplyScalingRecommendationMutationOptions = Apollo.BaseMutationOptions; +export const ClusterRegistrationDocument = gql` + query ClusterRegistration($id: ID, $machineId: String) { + clusterRegistration(id: $id, machineId: $machineId) { + ...ClusterRegistration + } +} + ${ClusterRegistrationFragmentDoc}`; + +/** + * __useClusterRegistrationQuery__ + * + * To run a query within a React component, call `useClusterRegistrationQuery` and pass it any options that fit your needs. + * When your component renders, `useClusterRegistrationQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useClusterRegistrationQuery({ + * variables: { + * id: // value for 'id' + * machineId: // value for 'machineId' + * }, + * }); + */ +export function useClusterRegistrationQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(ClusterRegistrationDocument, options); + } +export function useClusterRegistrationLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(ClusterRegistrationDocument, options); + } +export function useClusterRegistrationSuspenseQuery(baseOptions?: Apollo.SuspenseQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useSuspenseQuery(ClusterRegistrationDocument, options); + } +export type ClusterRegistrationQueryHookResult = ReturnType; +export type ClusterRegistrationLazyQueryHookResult = ReturnType; +export type ClusterRegistrationSuspenseQueryHookResult = ReturnType; +export type ClusterRegistrationQueryResult = Apollo.QueryResult; +export const ClusterRegistrationsDocument = gql` + query ClusterRegistrations($after: String, $first: Int, $before: String, $last: Int) { + clusterRegistrations(after: $after, first: $first, before: $before, last: $last) { + pageInfo { + ...PageInfo + } + edges { + node { + ...ClusterRegistration + } + } + } +} + ${PageInfoFragmentDoc} +${ClusterRegistrationFragmentDoc}`; + +/** + * __useClusterRegistrationsQuery__ + * + * To run a query within a React component, call `useClusterRegistrationsQuery` and pass it any options that fit your needs. + * When your component renders, `useClusterRegistrationsQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useClusterRegistrationsQuery({ + * variables: { + * after: // value for 'after' + * first: // value for 'first' + * before: // value for 'before' + * last: // value for 'last' + * }, + * }); + */ +export function useClusterRegistrationsQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(ClusterRegistrationsDocument, options); + } +export function useClusterRegistrationsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(ClusterRegistrationsDocument, options); + } +export function useClusterRegistrationsSuspenseQuery(baseOptions?: Apollo.SuspenseQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useSuspenseQuery(ClusterRegistrationsDocument, options); + } +export type ClusterRegistrationsQueryHookResult = ReturnType; +export type ClusterRegistrationsLazyQueryHookResult = ReturnType; +export type ClusterRegistrationsSuspenseQueryHookResult = ReturnType; +export type ClusterRegistrationsQueryResult = Apollo.QueryResult; +export const CreateClusterRegistrationDocument = gql` + mutation CreateClusterRegistration($attributes: ClusterRegistrationCreateAttributes!) { + createClusterRegistration(attributes: $attributes) { + ...ClusterRegistration + } +} + ${ClusterRegistrationFragmentDoc}`; +export type CreateClusterRegistrationMutationFn = Apollo.MutationFunction; + +/** + * __useCreateClusterRegistrationMutation__ + * + * To run a mutation, you first call `useCreateClusterRegistrationMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useCreateClusterRegistrationMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [createClusterRegistrationMutation, { data, loading, error }] = useCreateClusterRegistrationMutation({ + * variables: { + * attributes: // value for 'attributes' + * }, + * }); + */ +export function useCreateClusterRegistrationMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(CreateClusterRegistrationDocument, options); + } +export type CreateClusterRegistrationMutationHookResult = ReturnType; +export type CreateClusterRegistrationMutationResult = Apollo.MutationResult; +export type CreateClusterRegistrationMutationOptions = Apollo.BaseMutationOptions; +export const UpdateClusterRegistrationDocument = gql` + mutation UpdateClusterRegistration($id: ID!, $attributes: ClusterRegistrationUpdateAttributes!) { + updateClusterRegistration(id: $id, attributes: $attributes) { + ...ClusterRegistration + } +} + ${ClusterRegistrationFragmentDoc}`; +export type UpdateClusterRegistrationMutationFn = Apollo.MutationFunction; + +/** + * __useUpdateClusterRegistrationMutation__ + * + * To run a mutation, you first call `useUpdateClusterRegistrationMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useUpdateClusterRegistrationMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [updateClusterRegistrationMutation, { data, loading, error }] = useUpdateClusterRegistrationMutation({ + * variables: { + * id: // value for 'id' + * attributes: // value for 'attributes' + * }, + * }); + */ +export function useUpdateClusterRegistrationMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(UpdateClusterRegistrationDocument, options); + } +export type UpdateClusterRegistrationMutationHookResult = ReturnType; +export type UpdateClusterRegistrationMutationResult = Apollo.MutationResult; +export type UpdateClusterRegistrationMutationOptions = Apollo.BaseMutationOptions; +export const DeleteClusterRegistrationDocument = gql` + mutation DeleteClusterRegistration($id: ID!) { + deleteClusterRegistration(id: $id) { + ...ClusterRegistration + } +} + ${ClusterRegistrationFragmentDoc}`; +export type DeleteClusterRegistrationMutationFn = Apollo.MutationFunction; + +/** + * __useDeleteClusterRegistrationMutation__ + * + * To run a mutation, you first call `useDeleteClusterRegistrationMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useDeleteClusterRegistrationMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [deleteClusterRegistrationMutation, { data, loading, error }] = useDeleteClusterRegistrationMutation({ + * variables: { + * id: // value for 'id' + * }, + * }); + */ +export function useDeleteClusterRegistrationMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(DeleteClusterRegistrationDocument, options); + } +export type DeleteClusterRegistrationMutationHookResult = ReturnType; +export type DeleteClusterRegistrationMutationResult = Apollo.MutationResult; +export type DeleteClusterRegistrationMutationOptions = Apollo.BaseMutationOptions; export const GroupsDocument = gql` query Groups($q: String, $first: Int = 20, $after: String) { groups(q: $q, first: $first, after: $after) { @@ -25171,6 +25444,8 @@ export const namedOperations = { ClusterUsageHistory: 'ClusterUsageHistory', ClusterUsageNamespaces: 'ClusterUsageNamespaces', ClusterUsageScalingRecommendations: 'ClusterUsageScalingRecommendations', + ClusterRegistration: 'ClusterRegistration', + ClusterRegistrations: 'ClusterRegistrations', Groups: 'Groups', SearchGroups: 'SearchGroups', GroupMembers: 'GroupMembers', @@ -25300,6 +25575,9 @@ export const namedOperations = { SelfManage: 'SelfManage', KickService: 'KickService', ApplyScalingRecommendation: 'ApplyScalingRecommendation', + CreateClusterRegistration: 'CreateClusterRegistration', + UpdateClusterRegistration: 'UpdateClusterRegistration', + DeleteClusterRegistration: 'DeleteClusterRegistration', CreateGroupMember: 'CreateGroupMember', DeleteGroupMember: 'DeleteGroupMember', CreateGroup: 'CreateGroup', @@ -25443,6 +25721,8 @@ export const namedOperations = { ClusterUsageHistory: 'ClusterUsageHistory', ClusterNamespaceUsage: 'ClusterNamespaceUsage', ClusterScalingRecommendation: 'ClusterScalingRecommendation', + ClusterRegistration: 'ClusterRegistration', + Tag: 'Tag', GroupMember: 'GroupMember', Group: 'Group', KubernetesCluster: 'KubernetesCluster', @@ -25511,6 +25791,7 @@ export const namedOperations = { AccessTokenAudit: 'AccessTokenAudit', SharedSecret: 'SharedSecret', User: 'User', + UserTiny: 'UserTiny', Invite: 'Invite', RoleBinding: 'RoleBinding', Role: 'Role', diff --git a/assets/src/graph/edge.graphql b/assets/src/graph/edge.graphql new file mode 100644 index 0000000000..443511cfbf --- /dev/null +++ b/assets/src/graph/edge.graphql @@ -0,0 +1,75 @@ +fragment ClusterRegistration on ClusterRegistration { + id + insertedAt + updatedAt + machineId + name + handle + metadata + tags { + ...Tag + } + creator { + ...UserTiny + } + project { + ...ProjectTiny + } +} + +fragment Tag on Tag { + name + value +} + +query ClusterRegistration($id: ID, $machineId: String) { + clusterRegistration(id: $id, machineId: $machineId) { + ...ClusterRegistration + } +} + +query ClusterRegistrations( + $after: String + $first: Int + $before: String + $last: Int +) { + clusterRegistrations( + after: $after + first: $first + before: $before + last: $last + ) { + pageInfo { + ...PageInfo + } + edges { + node { + ...ClusterRegistration + } + } + } +} + +mutation CreateClusterRegistration( + $attributes: ClusterRegistrationCreateAttributes! +) { + createClusterRegistration(attributes: $attributes) { + ...ClusterRegistration + } +} + +mutation UpdateClusterRegistration( + $id: ID! + $attributes: ClusterRegistrationUpdateAttributes! +) { + updateClusterRegistration(id: $id, attributes: $attributes) { + ...ClusterRegistration + } +} + +mutation DeleteClusterRegistration($id: ID!) { + deleteClusterRegistration(id: $id) { + ...ClusterRegistration + } +} diff --git a/assets/src/graph/users.graphql b/assets/src/graph/users.graphql index c3b081dc18..49217cb9b3 100644 --- a/assets/src/graph/users.graphql +++ b/assets/src/graph/users.graphql @@ -17,6 +17,12 @@ fragment User on User { } } +fragment UserTiny on User { + name + email + profile +} + fragment Invite on Invite { secureId } diff --git a/assets/src/routes/consoleRoutes.tsx b/assets/src/routes/consoleRoutes.tsx index 016d08bdc5..df229c711e 100644 --- a/assets/src/routes/consoleRoutes.tsx +++ b/assets/src/routes/consoleRoutes.tsx @@ -17,6 +17,7 @@ import { secretsRoutes } from './secretsRoute' import { securityRoutes } from './securityRoutes' import { settingsRoutes } from './settingsRoutes' import { stacksRoutes } from './stacksRoutes' +import { edgeRoutes } from './edgeRoutes.tsx' const profileRoutes = [ } + />, +]