From 75bb6d09f930bcc6bd264f1f4e41dd9bc51edb9b Mon Sep 17 00:00:00 2001 From: Piyush Kumar Date: Thu, 28 Nov 2024 15:33:27 +0530 Subject: [PATCH] update msvc page --- fake-data-generator/gen.ts | 3 +- gql-queries-generator/doc/queries.graphql | 69 + .../routes/_main+/$account+/_layout.tsx | 23 +- .../$helmchart+/useHelmChartContext.tsx | 87 +- .../helm-charts/handle-helm-chart.tsx | 20 +- .../helm-utils/use-fetch-helmcharts.tsx | 32 +- .../workloads+/new-helm-chart/route.tsx | 46 +- .../backend-services-resources-V2.tsx | 47 +- .../handle-backend-service.tsx | 396 +++++- .../$account+/managed-services/route.tsx | 24 +- .../msvc+/$msv+/settings+/general/route.tsx | 18 +- .../$account+/new-managed-service/_index.tsx | 14 +- .../managed-service-layout-v2.tsx | 1157 +++++++++++++++++ .../gql/queries/managed-templates-queries.ts | 142 ++ src/apps/console/utils/commons.tsx | 52 +- src/generated/gql/sdl.graphql | 3 +- src/generated/gql/server.ts | 68 + 17 files changed, 2050 insertions(+), 151 deletions(-) create mode 100644 src/apps/console/routes/_main+/$account+/new-managed-service/managed-service-layout-v2.tsx diff --git a/fake-data-generator/gen.ts b/fake-data-generator/gen.ts index 8df42f000..17d7d8ccc 100644 --- a/fake-data-generator/gen.ts +++ b/fake-data-generator/gen.ts @@ -37,7 +37,8 @@ const types: string[] = [ 'ConsoleListRegistryImagesQuery', 'ConsoleListImagePullSecretsQuery', 'ConsoleListHelmChartsQuery', - 'ConsoleListServiceBindingQuery' + 'ConsoleListServiceBindingQuery', + 'ConsoleListMSvPluginsQuery', ]; async function fake(files: string[], types: string[] = []) { diff --git a/gql-queries-generator/doc/queries.graphql b/gql-queries-generator/doc/queries.graphql index f5436fe2b..7ae969a73 100644 --- a/gql-queries-generator/doc/queries.graphql +++ b/gql-queries-generator/doc/queries.graphql @@ -3402,6 +3402,75 @@ query consoleListMSvTemplates { } } +query consoleGetMSvPlugin($category: String!, $name: String!) { + core_getManagedServicePlugin(category: $category, name: $name) { + meta { + logo + } + plugin + spec { + apiVersion + services { + active + description + inputs { + defaultValue + displayUnit + input + label + max + min + multiplier + required + type + unit + } + kind + resources { + description + kind + } + } + } + } +} + +query consoleListMSvPlugins { + core_listManagedServicePlugins { + category + items { + meta { + logo + } + plugin + spec { + apiVersion + services { + active + description + inputs { + defaultValue + displayUnit + input + label + max + min + multiplier + required + type + unit + } + kind + resources { + description + kind + } + } + } + } + } +} + query consoleGetManagedResource($name: String!, $msvcName: String, $envName: String) { core_getManagedResource(name: $name, msvcName: $msvcName, envName: $envName) { accountName diff --git a/src/apps/console/routes/_main+/$account+/_layout.tsx b/src/apps/console/routes/_main+/$account+/_layout.tsx index d9ec809da..9ab09adfe 100644 --- a/src/apps/console/routes/_main+/$account+/_layout.tsx +++ b/src/apps/console/routes/_main+/$account+/_layout.tsx @@ -1,3 +1,4 @@ +import Popup from '@kloudlite/design-system/molecule/popup'; import { redirect } from '@remix-run/node'; import { Link, @@ -9,7 +10,6 @@ import { useParams, } from '@remix-run/react'; import { ReactNode, useEffect, useRef, useState } from 'react'; -import Popup from '@kloudlite/design-system/molecule/popup'; import { Buildings, Check, @@ -33,7 +33,11 @@ import { cn } from '@kloudlite/design-system/utils'; import MenuSelect, { SelectItem } from '~/console/components/menu-select'; import ClusterStatusProvider from '~/console/hooks/use-cluster-status-v3'; import { useConsoleApi } from '~/console/server/gql/api-provider'; -import { IMSvTemplates } from '~/console/server/gql/queries/managed-templates-queries'; +import { clustersStatusMap } from '~/console/server/gql/queries/cluster-queries'; +import { + IMsvPlugins, + IMSvTemplates, +} from '~/console/server/gql/queries/managed-templates-queries'; import { GQLServerHandler } from '~/console/server/gql/saved-queries'; import { ensureAccountClientSide, @@ -47,7 +51,6 @@ import withContext from '~/root/lib/app-setup/with-contxt'; import { useSearch } from '~/root/lib/client/helpers/search-filter'; import useCustomSwr from '~/root/lib/client/hooks/use-custom-swr'; import { handleError } from '~/root/lib/utils/common'; -import { clustersStatusMap } from '~/console/server/gql/queries/cluster-queries'; import { IConsoleRootContext } from '../_layout/_layout'; export const loader = async (ctx: IExtRemixCtx) => { @@ -70,6 +73,13 @@ export const loader = async (ctx: IExtRemixCtx) => { throw msvError[0]; } + const { data: msvPlugins, errors: msvPluginError } = await GQLServerHandler( + ctx.request + ).listMSvPlugins({}); + if (msvPluginError) { + throw msvPluginError[0]; + } + const { data: clusterList, errors: clusterError } = await GQLServerHandler( ctx.request ).listClusterStatus({ @@ -92,6 +102,7 @@ export const loader = async (ctx: IExtRemixCtx) => { return withContext(ctx, { msvtemplates: msvTemplates, + msvPlugins, account: data, clustersMap: clusterList, }); @@ -101,6 +112,7 @@ export const loader = async (ctx: IExtRemixCtx) => { return k as { account: typeof acccountData; msvtemplates: IMSvTemplates; + msvPlugins: IMsvPlugins; clustersMap: clustersStatusMap; }; } @@ -179,7 +191,8 @@ const _AccountMenu = ({ account }: { account: IAccount }) => { }; const Account = () => { - const { account, msvtemplates, clustersMap } = useLoaderData(); + const { account, msvtemplates, msvPlugins, clustersMap } = + useLoaderData(); const rootContext = useOutletContext(); const { unloadState, reset, proceed } = useUnsavedChanges(); @@ -201,6 +214,7 @@ const Account = () => { ...rootContext, account, msvtemplates, + msvPlugins, clustersMap: cm, setclustersMap: setCm, }} @@ -520,6 +534,7 @@ export const handle = ({ account }: any) => { export interface IAccountContext extends IConsoleRootContext { account: LoaderResult['account']; msvtemplates: IMSvTemplates; + msvPlugins: IMsvPlugins; clustersMap: clustersStatusMap; setClustersMap: React.Dispatch>; } diff --git a/src/apps/console/routes/_main+/$account+/env+/$environment+/workloads+/helm-chart+/$helmchart+/useHelmChartContext.tsx b/src/apps/console/routes/_main+/$account+/env+/$environment+/workloads+/helm-chart+/$helmchart+/useHelmChartContext.tsx index ffeef7901..7f71a3783 100644 --- a/src/apps/console/routes/_main+/$account+/env+/$environment+/workloads+/helm-chart+/$helmchart+/useHelmChartContext.tsx +++ b/src/apps/console/routes/_main+/$account+/env+/$environment+/workloads+/helm-chart+/$helmchart+/useHelmChartContext.tsx @@ -1,49 +1,70 @@ -import { createContext, ReactNode, useContext, useEffect, useState } from "react"; -import { HelmChartIn } from "~/root/src/generated/gql/server"; +import { + createContext, + ReactNode, + useContext, + useEffect, + useState, +} from 'react'; +import { HelmChartIn } from '~/root/src/generated/gql/server'; const HelmChartContext = createContext<{ - helmChart: HelmChartIn, - readOnlyHelmChart: HelmChartIn, - setHelmChart: (helmChart: HelmChartIn) => void - setReadOnlyHelmChart: (helmChart: HelmChartIn) => void + helmChart: HelmChartIn; + readOnlyHelmChart: HelmChartIn; + setHelmChart: (helmChart: HelmChartIn) => void; + setReadOnlyHelmChart: (helmChart: HelmChartIn) => void; }>({ helmChart: { - displayName: "" - }, readOnlyHelmChart: { - displayName: "" - }, setHelmChart: () => { }, setReadOnlyHelmChart() { - + displayName: '', + }, + readOnlyHelmChart: { + displayName: '', }, -}) + setHelmChart: () => {}, + setReadOnlyHelmChart() {}, +}); -const HelmChartContextProvider = ({ initialHelmChartState, children }: { - initialHelmChartState: - HelmChartIn, children?: ReactNode +const HelmChartContextProvider = ({ + initialHelmChartState, + children, +}: { + initialHelmChartState: HelmChartIn; + children?: ReactNode; }) => { - const [helmChart, setHelmChart] = useState(initialHelmChartState) - const [readOnlyHelmChart, setReadOnlyHelmChart] = useState(initialHelmChartState) + const [helmChart, setHelmChart] = useState( + initialHelmChartState + ); + const [readOnlyHelmChart, setReadOnlyHelmChart] = useState( + initialHelmChartState + ); useEffect(() => { - setHelmChart(initialHelmChartState) - setReadOnlyHelmChart(initialHelmChartState) + setHelmChart(initialHelmChartState); + setReadOnlyHelmChart(initialHelmChartState); - console.log("put...pp") - }, [initialHelmChartState]) + console.log('put...pp'); + }, [initialHelmChartState]); const putHelmChart = (h: HelmChartIn) => { - setHelmChart(h) - console.log("put") - } + setHelmChart(h); + console.log('put'); + }; - return {children} -} + return ( + + {children} + + ); +}; export const useHelmChartState = () => { - return useContext(HelmChartContext) -} + return useContext(HelmChartContext); +}; -export default HelmChartContextProvider +export default HelmChartContextProvider; diff --git a/src/apps/console/routes/_main+/$account+/env+/$environment+/workloads+/helm-charts/handle-helm-chart.tsx b/src/apps/console/routes/_main+/$account+/env+/$environment+/workloads+/helm-charts/handle-helm-chart.tsx index 0ebbc3c91..767067d93 100644 --- a/src/apps/console/routes/_main+/$account+/env+/$environment+/workloads+/helm-charts/handle-helm-chart.tsx +++ b/src/apps/console/routes/_main+/$account+/env+/$environment+/workloads+/helm-charts/handle-helm-chart.tsx @@ -1,6 +1,8 @@ /* eslint-disable react/destructuring-assignment */ import { TextInput } from '@kloudlite/design-system/atoms/input'; import Popup from '@kloudlite/design-system/molecule/popup'; +import { useOutletContext } from '@remix-run/react'; +import yaml from 'js-yaml'; import { IDialogBase } from '~/console/components/types.d'; import { useConsoleApi } from '~/console/server/gql/api-provider'; import { IHelmCharts } from '~/console/server/gql/queries/helm-chart-queries'; @@ -9,19 +11,17 @@ import { useReload } from '~/root/lib/client/helpers/reloader'; import useForm, { dummyEvent } from '~/root/lib/client/hooks/use-form'; import Yup from '~/root/lib/server/helpers/yup'; import { handleError } from '~/root/lib/utils/common'; -import yaml from 'js-yaml'; -import { useOutletContext } from '@remix-run/react'; -import { useEffect, useRef, useState } from 'react'; import Select from '@kloudlite/design-system/atoms/select'; +import { useEffect, useRef, useState } from 'react'; import { NameIdView } from '~/console/components/name-id-view'; import ExtendedFilledTab from '~/console/components/extended-filled-tab'; import { keyconstants } from '~/console/server/r-utils/key-constants'; -import { IEnvironmentContext } from '../../_layout'; -import CodeEditorClient from '~/root/lib/client/components/editor-client'; import { LoadingPlaceHolder } from '~/console/components/loading'; +import CodeEditorClient from '~/root/lib/client/components/editor-client'; +import { IEnvironmentContext } from '../../_layout'; import useFetchHelmCharts from './helm-utils/use-fetch-helmcharts'; import useFetchHelmValue from './helm-utils/use-fetch-helmvalues'; @@ -38,7 +38,7 @@ type IHelmDoc = { const filterUniqueVersions = (versions: IHelmDoc['entries']['keys']) => { return versions.filter( (obj, index, self) => - index === self.findIndex((t) => t.version === obj.version), + index === self.findIndex((t) => t.version === obj.version) ); }; @@ -167,8 +167,8 @@ const Root = (props: IDialog) => { setChartVersions( filterUniqueVersions( helmCharts.find((v) => v.value === props.data.spec?.chartName) - ?.item || [], - ), + ?.item || [] + ) ); setChartName({ label: props.data.spec?.chartName || '', @@ -215,7 +215,7 @@ const Root = (props: IDialog) => { errors={errors.name} handleChange={handleChange} nameErrorLabel="isNameError" - isUpdate={true} + isUpdate /> { } lang="yaml" onChange={(e) => { - const path = editorRef.current.getModel().uri.path; + const { path } = editorRef.current.getModel().uri; if ( values.activeTab === 'values' && diff --git a/src/apps/console/routes/_main+/$account+/env+/$environment+/workloads+/helm-charts/helm-utils/use-fetch-helmcharts.tsx b/src/apps/console/routes/_main+/$account+/env+/$environment+/workloads+/helm-charts/helm-utils/use-fetch-helmcharts.tsx index 7e69cd69c..6a15e4375 100644 --- a/src/apps/console/routes/_main+/$account+/env+/$environment+/workloads+/helm-charts/helm-utils/use-fetch-helmcharts.tsx +++ b/src/apps/console/routes/_main+/$account+/env+/$environment+/workloads+/helm-charts/helm-utils/use-fetch-helmcharts.tsx @@ -1,6 +1,6 @@ import axios from 'axios'; -import { useEffect, useState } from 'react'; import yaml from 'js-yaml'; +import { useEffect, useState } from 'react'; type IHelmDoc = { apiVersion: string; @@ -10,10 +10,16 @@ type IHelmDoc = { generated: string; }; -type IHelmChart = - Array<{ label: string; value: string; item: IHelmDoc['entries']['key'] }> +type IHelmChart = Array<{ + label: string; + value: string; + item: IHelmDoc['entries']['key']; +}>; -const useFetchHelmCharts = ({ repoUrl }: { repoUrl?: string }, onFetch?: (data: IHelmChart) => void) => { +const useFetchHelmCharts = ( + { repoUrl }: { repoUrl?: string }, + onFetch?: (data: IHelmChart) => void +) => { const [loading, setLoading] = useState(false); const [error, setError] = useState(false); const [helmCharts, setHelmCharts] = useState([]); @@ -24,16 +30,13 @@ const useFetchHelmCharts = ({ repoUrl }: { repoUrl?: string }, onFetch?: (data: setError(false); const res = await axios.get(`/helmchart-api?url=${repoUrl}`); const repos = yaml.load(res.data, { json: true }) as IHelmDoc; - const d = - Object.entries(repos.entries).map(([key, value]) => ({ - label: key, - value: key, - item: value, - })) - setHelmCharts( - d - ); - onFetch?.(d) + const d = Object.entries(repos.entries).map(([key, value]) => ({ + label: key, + value: key, + item: value, + })); + setHelmCharts(d); + onFetch?.(d); } catch (error) { setError(true); setHelmCharts([]); @@ -43,6 +46,7 @@ const useFetchHelmCharts = ({ repoUrl }: { repoUrl?: string }, onFetch?: (data: }; useEffect(() => { + console.log('repoUrl', repoUrl); if (repoUrl) { fetchHelmCharts(); } diff --git a/src/apps/console/routes/_main+/$account+/env+/$environment+/workloads+/new-helm-chart/route.tsx b/src/apps/console/routes/_main+/$account+/env+/$environment+/workloads+/new-helm-chart/route.tsx index 9cd7327d8..a244fa890 100644 --- a/src/apps/console/routes/_main+/$account+/env+/$environment+/workloads+/new-helm-chart/route.tsx +++ b/src/apps/console/routes/_main+/$account+/env+/$environment+/workloads+/new-helm-chart/route.tsx @@ -1,30 +1,30 @@ +import Select from '@kloudlite/design-system/atoms/select'; +import { toast } from '@kloudlite/design-system/molecule/toast'; +import { cn } from '@kloudlite/design-system/utils'; import { useNavigate, useOutletContext } from '@remix-run/react'; -import MultiStepProgress, { - useMultiStepProgress, -} from '~/console/components/multi-step-progress'; -import MultiStepProgressWrapper from '~/console/components/multi-step-progress-wrapper'; -import { useConsoleApi } from '~/console/server/gql/api-provider'; +import yaml from 'js-yaml'; +import { useRef, useState } from 'react'; +import FillerHelm from '~/console/assets/filler-helm'; import { BottomNavigation, ReviewComponent, } from '~/console/components/commons'; +import ExtendedFilledTab from '~/console/components/extended-filled-tab'; +import MultiStepProgress, { + useMultiStepProgress, +} from '~/console/components/multi-step-progress'; +import MultiStepProgressWrapper from '~/console/components/multi-step-progress-wrapper'; import { NameIdView } from '~/console/components/name-id-view'; +import { useConsoleApi } from '~/console/server/gql/api-provider'; +import { parseName } from '~/console/server/r-utils/common'; +import { keyconstants } from '~/console/server/r-utils/key-constants'; +import CodeEditorClient from '~/root/lib/client/components/editor-client'; import useForm, { dummyEvent } from '~/root/lib/client/hooks/use-form'; import Yup from '~/root/lib/server/helpers/yup'; -import Select from '@kloudlite/design-system/atoms/select'; -import { useRef, useState } from 'react'; -import { cn } from '@kloudlite/design-system/utils'; -import { toast } from '@kloudlite/design-system/molecule/toast'; -import yaml from 'js-yaml'; -import ExtendedFilledTab from '~/console/components/extended-filled-tab'; -import { keyconstants } from '~/console/server/r-utils/key-constants'; -import { IEnvironmentContext } from '../../_layout'; -import { parseName } from '~/console/server/r-utils/common'; import { handleError } from '~/root/lib/utils/common'; -import CodeEditorClient from '~/root/lib/client/components/editor-client'; -import FillerHelm from '~/console/assets/filler-helm'; -import useFetchHelmValue from '../helm-charts/helm-utils/use-fetch-helmvalues'; +import { IEnvironmentContext } from '../../_layout'; import useFetchHelmCharts from '../helm-charts/helm-utils/use-fetch-helmcharts'; +import useFetchHelmValue from '../helm-charts/helm-utils/use-fetch-helmvalues'; import useHelmRepoSearch from '../helm-charts/helm-utils/use-helm-repo-search'; type IHelmDoc = { @@ -52,7 +52,7 @@ const repoRenderer = ({ const filterUniqueVersions = (versions: IHelmDoc['entries']['keys']) => { return versions.filter( (obj, index, self) => - index === self.findIndex((t) => t.version === obj.version), + index === self.findIndex((t) => t.version === obj.version) ); }; @@ -115,21 +115,21 @@ const HelmChartLayout = () => { 'Chart Name is required', (v) => { return !(currentStep === 2 && !v); - }, + } ), chartRepoURL: Yup.string().test( 'required', 'Chart Repo Url is required', (v) => { return !(currentStep === 2 && !v); - }, + } ), chartVersion: Yup.string().test( 'required', 'Chart Version is required', (v) => { return !(currentStep === 2 && !v); - }, + } ), }), @@ -310,7 +310,7 @@ const HelmChartLayout = () => { searchable size="lg" disabled={helmCharts.length === 0 || repoLoading || !selectedRepo} - //@ts-ignore + // @ts-ignore value={chartName?.value} options={async () => helmCharts} loading={!errors.chartVersion && helmChartsLoading} @@ -390,7 +390,7 @@ const HelmChartLayout = () => { } lang="yaml" onChange={(e) => { - const path = editorRef.current.getModel().uri.path; + const { path } = editorRef.current.getModel().uri; if ( values.activeTab === 'values' && diff --git a/src/apps/console/routes/_main+/$account+/managed-services/backend-services-resources-V2.tsx b/src/apps/console/routes/_main+/$account+/managed-services/backend-services-resources-V2.tsx index 5adc8efc1..ea2e58147 100644 --- a/src/apps/console/routes/_main+/$account+/managed-services/backend-services-resources-V2.tsx +++ b/src/apps/console/routes/_main+/$account+/managed-services/backend-services-resources-V2.tsx @@ -4,11 +4,11 @@ import { generateKey, titleCase } from '@kloudlite/design-system/utils'; import { Link, useOutletContext, useParams } from '@remix-run/react'; import { useState } from 'react'; import { + listClass, ListItem, ListItemV2, ListTitle, ListTitleV2, - listClass, } from '~/console/components/console-list-components'; import DeleteDialog from '~/console/components/delete-dialog'; import Grid from '~/console/components/grid'; @@ -20,14 +20,17 @@ import { SyncStatusV2 } from '~/console/components/sync-status'; import { useClusterStatusV3 } from '~/console/hooks/use-cluster-status-v3'; import { useConsoleApi } from '~/console/server/gql/api-provider'; import { IClusterMSvs } from '~/console/server/gql/queries/cluster-managed-services-queries'; -import { IMSvTemplates } from '~/console/server/gql/queries/managed-templates-queries'; +import { + IMsvPlugins, + IMSvTemplates, +} from '~/console/server/gql/queries/managed-templates-queries'; import { ExtractNodeType, parseName, parseUpdateOrCreatedBy, parseUpdateOrCreatedOn, } from '~/console/server/r-utils/common'; -import { getManagedTemplate } from '~/console/utils/commons'; +import { getManagedPlugin, getManagedTemplate } from '~/console/utils/commons'; import { useReload } from '~/root/lib/client/helpers/reloader'; import { useWatchReload } from '~/root/lib/client/helpers/socket/useWatch'; import { handleError } from '~/root/lib/utils/common'; @@ -38,12 +41,21 @@ import CloneManagedService from './clone-managed-service'; const RESOURCE_NAME = 'managed service'; type BaseType = ExtractNodeType; -const parseItem = (item: BaseType, templates: IMSvTemplates) => { +const parseItem = ( + item: BaseType, + templates: IMSvTemplates, + plugins: IMsvPlugins +) => { const template = getManagedTemplate({ templates, kind: item.spec?.msvcSpec?.serviceTemplate?.kind || '', apiVersion: item.spec?.msvcSpec?.serviceTemplate?.apiVersion || '', }); + const plugin = getManagedPlugin({ + plugins, + apiVersion: item.spec?.msvcSpec?.serviceTemplate?.apiVersion || '', + kind: item.spec?.msvcSpec?.serviceTemplate?.kind || '', + }); return { name: item?.displayName, id: parseName(item), @@ -52,6 +64,7 @@ const parseItem = (item: BaseType, templates: IMSvTemplates) => { time: parseUpdateOrCreatedOn(item), }, logo: template?.logoUrl, + logoUrl: plugin?.meta?.logo, }; }; @@ -102,15 +115,20 @@ const ExtraButton = ({ item, onAction }: IExtraButton) => { interface IResource { items: BaseType[]; templates: IMSvTemplates; + plugins: IMsvPlugins; onAction: OnAction; } -const GridView = ({ items, templates, onAction }: IResource) => { +const GridView = ({ items, templates, plugins, onAction }: IResource) => { const { account, project } = useParams(); return ( {items.map((item, index) => { - const { name, id, logo, updateInfo } = parseItem(item, templates); + const { name, id, logo, updateInfo } = parseItem( + item, + templates, + plugins + ); const keyPrefix = `${RESOURCE_NAME}-${id}-${index}`; return ( { ); }; -const ListView = ({ items, templates, onAction }: IResource) => { +const ListView = ({ items, templates, plugins, onAction }: IResource) => { const { account } = useOutletContext(); const { clustersMap: clusterStatus } = useClusterStatusV3({ clusterNames: items.map((i) => i.clusterName), @@ -204,7 +222,11 @@ const ListView = ({ items, templates, onAction }: IResource) => { ], rows: items.map((i) => { const isClusterOnline = !!clusterStatus[i.clusterName]?.isOnline; - const { name, id, logo, updateInfo } = parseItem(i, templates); + const { name, id, logo, updateInfo, logoUrl } = parseItem( + i, + templates, + plugins + ); return { columns: { name: { @@ -214,7 +236,11 @@ const ListView = ({ items, templates, onAction }: IResource) => { subtitle={id} avatar={
- {name} + {name}
} /> @@ -267,9 +293,11 @@ const ListView = ({ items, templates, onAction }: IResource) => { const BackendServicesResourcesV2 = ({ items = [], templates = [], + plugins = [], }: { items: BaseType[]; templates: IMSvTemplates; + plugins: IMsvPlugins; }) => { const { account } = useOutletContext(); useWatchReload( @@ -290,6 +318,7 @@ const BackendServicesResourcesV2 = ({ const props: IResource = { items, templates, + plugins, onAction: ({ action, item }) => { switch (action) { case 'clone': diff --git a/src/apps/console/routes/_main+/$account+/managed-services/handle-backend-service.tsx b/src/apps/console/routes/_main+/$account+/managed-services/handle-backend-service.tsx index 816e018a6..f767b7460 100644 --- a/src/apps/console/routes/_main+/$account+/managed-services/handle-backend-service.tsx +++ b/src/apps/console/routes/_main+/$account+/managed-services/handle-backend-service.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react/jsx-no-useless-fragment */ /* eslint-disable guard-for-in */ /* eslint-disable react/destructuring-assignment */ import { @@ -5,26 +6,67 @@ import { NumberInput, TextInput, } from '@kloudlite/design-system/atoms/input'; +import Select from '@kloudlite/design-system/atoms/select'; import { Switch } from '@kloudlite/design-system/atoms/switch'; import Popup from '@kloudlite/design-system/molecule/popup'; import { useEffect, useRef, useState } from 'react'; +import ExtendedFilledTab from '~/console/components/extended-filled-tab'; +import { LoadingPlaceHolder } from '~/console/components/loading'; import { NameIdView } from '~/console/components/name-id-view'; import { IDialogBase } from '~/console/components/types.d'; import { useConsoleApi } from '~/console/server/gql/api-provider'; import { IClusterMSvs } from '~/console/server/gql/queries/cluster-managed-services-queries'; -import { IMSvTemplates } from '~/console/server/gql/queries/managed-templates-queries'; +import { + IMSvPlugin, + IMsvPlugins, + IMSvTemplates, +} from '~/console/server/gql/queries/managed-templates-queries'; import { ExtractNodeType, parseName } from '~/console/server/r-utils/common'; +import { keyconstants } from '~/console/server/r-utils/key-constants'; import { getManagedTemplate } from '~/console/utils/commons'; +import CodeEditorClient from '~/root/lib/client/components/editor-client'; import { useReload } from '~/root/lib/client/helpers/reloader'; import useForm, { dummyEvent } from '~/root/lib/client/hooks/use-form'; import Yup from '~/root/lib/server/helpers/yup'; import { NN } from '~/root/lib/types/common'; import { handleError } from '~/root/lib/utils/common'; +import useFetchHelmCharts from '../env+/$environment+/workloads+/helm-charts/helm-utils/use-fetch-helmcharts'; +import useFetchHelmValue from '../env+/$environment+/workloads+/helm-charts/helm-utils/use-fetch-helmvalues'; type IDialog = IDialogBase> & { templates: IMSvTemplates; }; +type IHelmDoc = { + apiVersion: string; + entries: { + [key: string]: { version: string }[]; + }; + generated: string; +}; + +const valueEditorProps = { + height: '200px', + options: { + fontSize: 14, + padding: { + top: 20, + bottom: 20, + }, + tabSize: 2, + minimap: { + enabled: false, + }, + }, +}; + +const filterUniqueVersions = (versions: IHelmDoc['entries']['keys']) => { + return versions.filter( + (obj, index, self) => + index === self.findIndex((t) => t.version === obj.version) + ); +}; + type ISelectedService = { category: { name: string; @@ -34,6 +76,171 @@ type ISelectedService = { service?: NN[number]['items'][number]; } | null; +type ISelectedServicePlugins = { + category: { + name: string; + displayName: string; + }; + + service?: NN[number]['items'][number]; +} | null; + +const RenderHelmFields = ({ + values, + onChange, + errors, + fields, + annotations, +}: { + onChange: (e: string) => (e: { target: { value: any } }) => void; + values: any; + errors: { + [key: string]: string | undefined; + }; + fields: IMSvPlugin['spec']['services'][0]['inputs']; + annotations?: { [key: string]: string }; +}) => { + const [activeTab, setActiveTab] = useState('defaults'); + + const editorRef = useRef(); + + const [chartVersions, setChartVersions] = useState< + IHelmDoc['entries']['key'] + >([]); + + const { values: helmValues, isLoading: helmValuesLoading } = + useFetchHelmValue({ + packageId: annotations?.[keyconstants.helmChartRepoPackageId], + version: values.res.chart.version, + }); + + const { helmCharts, loading: helmChartsLoading } = useFetchHelmCharts({ + repoUrl: values.res.chart.url, + }); + + useEffect(() => { + if (helmCharts && helmCharts.length > 0) { + setChartVersions( + filterUniqueVersions( + helmCharts.find((v) => v.value === values.res.chart.name)?.item || [] + ) + ); + } + }, [helmCharts]); + + return ( +
+ {fields.map((field) => { + switch (field.input) { + case 'chart.url': + return ( + + ); + case 'chart.name': + return ( + + ); + case 'chart.version': + return ( + repos} + value={selectedRepo} + onChange={(value) => { + if (!repoSearchText.startsWith('https://')) { + onChange(`res.${field.input}`)(dummyEvent(value.repoUrl)); + } else { + onChange(`res.${field.input}`)(dummyEvent(value.value)); + } + setSelectedRepo(value.value); + onChange('helmPackageId')(dummyEvent(value.value)); + /* setHelmCharts([]); */ + }} + onSearch={(text) => { + setRepoSearchText(text); + // resetHelmFields(); + }} + valueRender={repoRenderer} + loading={repoLoading} + noOptionMessage={ +
+ Search for or enter the repo url +
+ } + // error={!!errors[fieldKey]} + // message={errors[fieldKey]} + /> + ); + case 'chart.name': + return ( + [ + ...chartVersions.map((cv) => ({ + label: cv.version, + value: cv.version, + })), + ]} + loading={helmChartsLoading} + onChange={(val) => { + onChange(`res.${field.input}`)(dummyEvent(val.value)); + setChartVersion(val); + }} + onSearch={() => true} + /> + ); + case 'helmValues': + return ( +
+ {helmValuesLoading ? ( + + ) : ( + chartVersion && ( +
+ { + // onChange('activeTab')(dummyEvent(e)); + setActiveTab(e); + }} + items={[ + { label: 'Defaults', value: 'defaults' }, + { + label: 'Values', + value: 'values', + }, + ]} + /> + { + const { path } = editorRef.current.getModel().uri; + + if ( + activeTab === 'values' && + path === '/values.yaml' + ) { + onChange('res.helmValues')(dummyEvent(e)); + } + }} + path={ + activeTab === 'defaults' + ? 'defaults.yaml' + : 'values.yaml' + } + onMount={(e) => { + editorRef.current = e; + }} + /> +
+ ) + )} +
+ ); + default: + return null; + } + })} +
+ ); +}; + +const RenderField = ({ + field, + value, + onChange, + errors, + fieldKey, +}: { + // field: IMSvTemplate['fields'][number]; + field: IMSvPlugin['spec']['services'][0]['inputs'][number]; + onChange: (e: string) => (e: { target: { value: any } }) => void; + value: any; + errors: { + [key: string]: string; + }; + fieldKey: string; +}) => { + const [qos, setQos] = useState(false); + // const editorRef = useRef(); + + if (field.type === 'Number') { + return ( + { + onChange(`res.${field.input}`)( + dummyEvent( + `${parseFloat(target.value) * (field.multiplier || 1)}${ + field.unit + }` + ) + ); + }} + suffix={field.displayUnit} + /> + ); + } + + if (field.type === 'String') { + return ( + + ); + } + + if (field.type === 'text/yaml') { + const v = typeof value === 'string' ? value : JSON.stringify(value); + return ( +
+
{field.label}
+ { + onChange(`res.${field.input}`)(dummyEvent(e)); + }} + path={field.input} + /> +
+ ); + } + + if (field.type === 'int-range') { + return ( +
+
{`${field.label}${ + field.required ? ' *' : '' + }`}
+
+
+
+ { + onChange(`res.${field.input}.min`)( + dummyEvent( + `${parseFloat(target.value) * (field.multiplier || 1)}${ + field.unit + }` + ) + ); + if (qos) { + onChange(`res.${field.input}.max`)( + dummyEvent( + `${parseFloat(target.value) * (field.multiplier || 1)}${ + field.unit + }` + ) + ); + } + }} + suffix={field.displayUnit} + /> +
+ +
+ { + onChange(`res.${field.input}.max`)( + dummyEvent( + `${parseFloat(target.value) * (field.multiplier || 1)}${ + field.unit + }` + ) + ); + }} + suffix={field.displayUnit} + /> +
+
+
+
+ ); + } + + if (field.type === 'Resource') { + return ( +
+
{`${field.label}${ + field.required ? ' *' : '' + }`}
+
+
+
+ { + onChange(`res.${field.input}.min`)( + dummyEvent( + `${parseFloat(target.value) * (field.multiplier || 1)}${ + field.unit + }` + ) + ); + if (qos) { + onChange(`res.${field.input}.max`)( + dummyEvent( + `${parseFloat(target.value) * (field.multiplier || 1)}${ + field.unit + }` + ) + ); + } + }} + suffix={field.displayUnit} + /> +
+ {!qos && ( +
+ { + onChange(`res.${field.input}.max`)( + dummyEvent( + `${parseFloat(target.value) * (field.multiplier || 1)}${ + field.unit + }` + ) + ); + }} + suffix={field.displayUnit} + /> +
+ )} +
+
+ { + setQos(_value); + if (_value) { + onChange(`res.${field.input}.max`)( + dummyEvent(`${value.min}`) + ); + } + }} + /> +
+
+
+ ); + } + return
unknown input type {field.type}
; +}; + +type ISelectedPlugin = { + category: string; + categoryDisplayName: string; + plugin: IMSvPlugin; +}; + +const TemplateView = ({ + handleSubmit, + values, + handleChange, + errors, + plugins, + isLoading, +}: { + handleSubmit: FormEventHandler; + values: Record; + errors: Record; + plugins: IMsvPlugins; + isLoading: boolean; + handleChange: (key: string) => (e: { target: { value: any } }) => void; +}) => { + return ( +
+
Create your managed services.
+ clusters} + // options={async () => [ + // ...((clusters && + // clusters.filter((c) => { + // return c.ready; + // })) || + // []), + // ]} + onChange={({ value }) => { + handleChange('clusterName')(dummyEvent(value)); + handleChange('nodepoolName')(dummyEvent('')); + }} + showclear + error={!!errors.clusterName} + message={errors.clusterName} + // loading={cIsLoading || byokCIsLoading} + /> + {getRenderField()} + + + + ); +}; + +const ReviewView = ({ + handleSubmit, + values, + isLoading, + onEdit, +}: { + values: Record; + onEdit: (step: number) => void; + handleSubmit: FormEventHandler; + isLoading?: boolean; +}) => { + const renderFieldView = () => { + const fields = Object.entries(values.res).filter( + ([k, _v]) => !['resources'].includes(k) + ); + if (fields.length > 0) { + return ( + { + onEdit(2); + }} + > +
+ {fields?.map(([key, value]) => { + const k = key as string; + const v = value; + if (key === 'helmValues') { + return null; + } + const getValueRenderer = () => { + if (typeof v === 'string') { + return
{v}
; + } + return ( +
+ {Object.entries(v || {}).map(([pKey, pValue]) => ( +
+ {titleCase(pKey)} + {' : '} + {pValue} +
+ ))} +
+ ); + }; + return ( +
+
+ {titleCase(k)} +
+ {getValueRenderer()} +
+ ); + })} +
+
+ ); + } + return null; + }; + return ( +
+
+ { + onEdit(2); + }} + > +
+
+
+ {values.displayName} +
+
{values.name}
+
+
+
+ + { + onEdit(1); + }} + > +
+
+
+ {values?.selectedPlugin?.categoryDisplayName} +
+
+ {values?.selectedPlugin?.categoryDisplayName} +
+
+
+
+ Cluster Name +
+
{values.clusterName}
+
+
+
+ + {renderFieldView()} + {values?.res?.resources && ( + { + onEdit(2); + }} + > +
+ {Object.entries(values?.res?.resources).map(([key, value]) => { + return ( +
+
+ {titleCase(key)} +
+
+ {Object.entries(value || {}).map(([pKey, pValue]) => ( +
+ {pKey} + {' : '} + {pValue} +
+ ))} +
+
+ ); + })} +
+
+ )} +
+ + + ); +}; + +// const ClusterSelectItem = ({ +// label, +// value, +// }: { +// label: string; +// value: string; +// }) => { +// return ( +//
+//
+//
{label}
+//
{value}
+//
+//
+// ); +// }; + +export const ManagedServiceLayoutV2 = () => { + const { account, msvPlugins } = useOutletContext(); + const navigate = useNavigate(); + const api = useConsoleApi(); + + // const rootUrl = `/${parseName(account)}/infra/${parseName( + // account + // )}/managed-services`; + + const rootUrl = `/${parseName(account)}/managed-services`; + + const { currentStep, jumpStep, nextStep } = useMultiStepProgress({ + defaultStep: 1, + totalSteps: 3, + }); + + const [clusterList, setClusterList] = useState([]); + const params = useParams(); + + const { clustersMap } = useClusterStatusV3({}); + + const getClusters = useCallback(async () => { + ensureAccountClientSide(params); + try { + const data = Object.values(clustersMap).map((cm) => { + if (cm == null) { + return {}; + } + + const { name, displayName, isOnline } = cm; + + return { + label: displayName, + value: name, + ready: isOnline, + disabled: () => !isOnline, + // eslint-disable-next-line react/no-unused-prop-types + render: ({ disabled }: { disabled: boolean }) => ( + + ), + }; + }); + setClusterList(data); + } catch (err) { + handleError(err); + } + }, []); + + useEffect(() => { + getClusters(); + }, []); + + const { values, errors, handleSubmit, handleChange, isLoading, setValues } = + useForm({ + initialValues: { + name: '', + displayName: '', + res: {}, + helmPackageId: '', + // selectedTemplate: null, + selectedPlugin: null, + isNameError: false, + clusterName: '', + nodepoolName: '', + }, + validationSchema: Yup.object().shape({ + name: Yup.string().test('required', 'Name is required', (v) => { + return !(currentStep === 2 && !v); + }), + displayName: Yup.string().test('required', 'Name is required', (v) => { + return !(currentStep === 2 && !v); + }), + clusterName: Yup.string().test( + 'required', + 'Cluster name is required', + (v) => { + return !(currentStep === 2 && !v); + } + ), + selectedPlugin: Yup.object({}).required('Plugin is required.'), + // @ts-ignore + res: Yup.object({}).test({ + name: 'res', + skipAbsent: true, + test(value, ctx) { + // eslint-disable-next-line react/no-this-in-sfc + const selfValue = this.parent; + + let vs = Yup.object({}); + + if (selfValue.selectedTemplate && currentStep === 2) { + vs = Yup.object( + flatMapValidations( + selfValue.selectedTemplate?.template?.fields.reduce( + (acc: any, curr: any) => { + return { ...acc, [curr.name]: curr }; + }, + {} + ) + ) + ); + } + + const res = vs.validateSync(value, { + abortEarly: false, + context: ctx, + }); + + return res; + }, + }), + }), + onSubmit: async (val) => { + const selectedPlugin = val.selectedPlugin as unknown as ISelectedPlugin; + const submit = async () => { + try { + if ( + !selectedPlugin.plugin.spec.apiVersion || + !selectedPlugin?.plugin?.spec.services[0].kind + ) { + throw new Error('Service apiversion or kind error.'); + } + const res = { ...val.res }; + if (selectedPlugin.plugin.plugin === 'HelmChart') { + // @ts-ignore + res.helmValues = res.helmValues ? yaml.dump(res.helmValues) : ''; + } + const { errors: e } = await api.createClusterMSv({ + service: { + displayName: val.displayName, + metadata: { + name: val.name, + annotations: { + [keyconstants.helmChartRepoPackageId]: values.helmPackageId, + }, + }, + clusterName: val.clusterName, + spec: { + msvcSpec: { + nodeSelector: { + [keyconstants.nodepoolName]: val.nodepoolName, + }, + serviceTemplate: { + apiVersion: selectedPlugin.plugin.spec.apiVersion, + kind: selectedPlugin.plugin.spec.services[0].kind, + spec: { + ...val.res, + }, + }, + }, + }, + }, + }); + if (e) { + throw e[0]; + } + toast.success('Managed service created successfully'); + navigate(rootUrl); + } catch (err) { + handleError(err); + } + }; + + switch (currentStep) { + case 1: + nextStep(); + break; + case 2: + nextStep(); + break; + case 3: + await submit(); + break; + default: + break; + } + }, + }); + + useEffect(() => { + const selectedPlugin = values.selectedPlugin as unknown as ISelectedPlugin; + if (selectedPlugin?.plugin?.spec?.services[0]?.inputs) { + setValues((v) => ({ + ...v, + res: { + ...flatM( + selectedPlugin.plugin?.spec.services[0].inputs.reduce( + (acc, curr) => { + return { ...acc, [curr.input]: curr }; + }, + {} + ) + ), + }, + })); + } + }, [values.selectedPlugin]); + + useEffect(() => { + setValues((v) => ({ + ...v, + clusterName: + clusterList.length > 0 + ? clusterList.find((c) => c.ready)?.value || '' + : '', + })); + }, [clusterList]); + + return ( + + + + + + + + + + + + + + ); +}; diff --git a/src/apps/console/server/gql/queries/managed-templates-queries.ts b/src/apps/console/server/gql/queries/managed-templates-queries.ts index 1d264180d..a9d200938 100644 --- a/src/apps/console/server/gql/queries/managed-templates-queries.ts +++ b/src/apps/console/server/gql/queries/managed-templates-queries.ts @@ -2,8 +2,12 @@ import gql from 'graphql-tag'; import { IExecutor } from '~/root/lib/server/helpers/execute-query-with-context'; import { NN } from '~/root/lib/types/common'; import { + ConsoleGetMSvPluginQuery, + ConsoleGetMSvPluginQueryVariables, ConsoleGetMSvTemplateQuery, ConsoleGetMSvTemplateQueryVariables, + ConsoleListMSvPluginsQuery, + ConsoleListMSvPluginsQueryVariables, ConsoleListMSvTemplatesQuery, ConsoleListMSvTemplatesQueryVariables, } from '~/root/src/generated/gql/server'; @@ -15,6 +19,14 @@ export type IMSvTemplates = NN< ConsoleListMSvTemplatesQuery['infra_listManagedServiceTemplates'] >; +export type IMSvPlugin = NN< + ConsoleGetMSvPluginQuery['core_getManagedServicePlugin'] +>; + +export type IMsvPlugins = NN< + ConsoleListMSvPluginsQuery['core_listManagedServicePlugins'] +>; + export const managedTemplateQueries = (executor: IExecutor) => ({ getMSvTemplate: executor( gql` @@ -136,4 +148,134 @@ export const managedTemplateQueries = (executor: IExecutor) => ({ vars(_: ConsoleListMSvTemplatesQueryVariables) {}, } ), + getMSvPlugin: executor( + gql` + query Core_getManagedServicePlugin($category: String!, $name: String!) { + core_getManagedServicePlugin(category: $category, name: $name) { + meta { + logo + } + plugin + spec { + apiVersion + services { + active + description + inputs { + defaultValue + displayUnit + input + label + max + min + multiplier + required + type + unit + } + kind + resources { + description + kind + } + } + } + } + } + `, + { + transformer(data: ConsoleGetMSvPluginQuery) { + return data.core_getManagedServicePlugin; + }, + vars(_: ConsoleGetMSvPluginQueryVariables) {}, + } + ), + listMSvPlugins: executor( + gql` + query Core_listManagedServicePlugins { + core_listManagedServicePlugins { + category + items { + meta { + logo + } + plugin + spec { + apiVersion + services { + active + description + inputs { + defaultValue + displayUnit + input + label + max + min + multiplier + required + type + unit + } + kind + resources { + description + kind + } + } + } + } + } + } + `, + { + transformer: (data: ConsoleListMSvPluginsQuery) => + data.core_listManagedServicePlugins, + vars(_: ConsoleListMSvPluginsQueryVariables) {}, + } + ), }); + +// export type InputField = { +// defaultValue: any; // Can be refined further based on actual data type +// displayUnit: string | null; +// input: string; +// label: string; +// max: number | null; +// min: number | null; +// multiplier: number | null; +// required: boolean; +// type: string; +// unit: string | null; +// }; + +// export type Resource = { +// description: string; +// kind: string; +// }; + +// export type Service = { +// active: boolean; +// description: string; +// inputs: InputField[]; +// kind: string; +// resources: Resource[]; +// }; + +// export type Spec = { +// apiVersion: string; +// services: Service[]; +// }; + +// export type PluginItem = { +// meta: { +// logo: string; +// }; +// plugin: string; +// spec: Spec; +// }; + +// export type IMsvPlugin = { +// // category: string; +// items: PluginItem; +// }; diff --git a/src/apps/console/utils/commons.tsx b/src/apps/console/utils/commons.tsx index c0ddbbab3..e27b7bdd7 100644 --- a/src/apps/console/utils/commons.tsx +++ b/src/apps/console/utils/commons.tsx @@ -1,17 +1,20 @@ +/* eslint-disable no-restricted-syntax */ /* eslint-disable guard-for-in */ +import { cn } from '@kloudlite/design-system/utils'; import { AWSlogoFill, ChevronRight, GoogleCloudlogo, } from '~/console/components/icons'; -import { Github__Com___Kloudlite___Operator___Apis___Common____Types__CloudProvider as CloudProviders } from '~/root/src/generated/gql/server'; -import { cn } from '@kloudlite/design-system/utils'; import yup from '~/root/lib/server/helpers/yup'; +import { Github__Com___Kloudlite___Operator___Apis___Common____Types__CloudProvider as CloudProviders } from '~/root/src/generated/gql/server'; +import { parseValue } from '../page-components/util'; import { + IMSvPlugin, + IMsvPlugins, IMSvTemplate, IMSvTemplates, } from '../server/gql/queries/managed-templates-queries'; -import { parseValue } from '../page-components/util'; export const getManagedTemplate = ({ templates, @@ -27,6 +30,31 @@ export const getManagedTemplate = ({ .find((t) => t.kind === kind && t.apiVersion === apiVersion); }; +export const getManagedPlugin = ({ + plugins, + kind, + apiVersion, +}: { + plugins: IMsvPlugins; + kind: string; + apiVersion: string; +}): IMSvPlugin | undefined => { + return Array.isArray(plugins) + ? plugins + .flatMap((t) => t.items.flat()) + .find( + (t) => + t.spec.services[0].kind === kind && t.spec.apiVersion === apiVersion + ) + : undefined; + // return plugins + // ?.flatMap((t) => t.items.flat()) + // .find( + // (t) => + // t.spec.services[0].kind === kind && t.spec.apiVersion === apiVersion + // ); +}; + export const getManagedTemplateLogo = ( templates: IMSvTemplates, msvcApiVersion: string @@ -192,14 +220,16 @@ export const flatM = ( string, { defaultValue: number | string | boolean; - inputType: string; + type: string; multiplier?: number; unit?: string; + input?: string; } > ) => { const flatJson = {}; for (const key in obj) { + console.log('key', key); const parts = key.split('.'); let temp: Record = flatJson; @@ -211,24 +241,26 @@ export const flatM = ( temp[part] = temp[part] || {}; if (index === parts.length - 1) { - temp[part] = obj[key].defaultValue + (obj[key].unit || ''); + temp[part] = (obj[key].defaultValue || 1) + (obj[key].unit || ''); if ( typeof obj[key].defaultValue === 'number' || typeof obj[key].defaultValue === 'bigint' ) { temp[part] = - Number(obj[key].defaultValue) * (obj[key].multiplier || 1) + + Number(obj[key].defaultValue || 1) * (obj[key].multiplier || 1) + (obj[key].unit || ''); } - - if (obj[key].inputType === 'Resource') { + if (obj[key].type === 'Resource' || obj[key].type === 'int-range') { + console.log('obj[key].defaultValue', obj[key].defaultValue); temp[part] = { min: - Number(obj[key].defaultValue) * (obj[key].multiplier || 1) + + Number(obj[key].defaultValue || 1) * + (obj[key].multiplier || 1) + (obj[key].unit || ''), max: - Number(obj[key].defaultValue) * (obj[key].multiplier || 1) + + Number(obj[key].defaultValue || 1) * + (obj[key].multiplier || 1) + (obj[key].unit || ''), }; } diff --git a/src/generated/gql/sdl.graphql b/src/generated/gql/sdl.graphql index 58ccbce80..8df228b88 100644 --- a/src/generated/gql/sdl.graphql +++ b/src/generated/gql/sdl.graphql @@ -3667,7 +3667,6 @@ type Mutation { core_interceptApp(appname: String!, deviceName: String!, envName: String!, intercept: Boolean!, portMappings: [Github__com___kloudlite___operator___apis___crds___v1__AppInterceptPortMappingsIn!]): Boolean! core_interceptAppOnLocalCluster(appname: String!, clusterName: String!, envName: String!, intercept: Boolean!, ipAddr: String!, portMappings: [Github__com___kloudlite___operator___apis___crds___v1__AppInterceptPortMappingsIn!]): Boolean! core_interceptExternalApp(deviceName: String!, envName: String!, externalAppName: String!, intercept: Boolean!, portMappings: [Github__com___kloudlite___operator___apis___crds___v1__AppInterceptPortMappingsIn!]): Boolean! - core_listManagedServicePlugins: [ManagedServicePlugins!] core_removeDeviceIntercepts(deviceName: String!, envName: String!): Boolean! core_setupDefaultEnvironment: Boolean! core_updateApp(app: AppIn!, envName: String!): App @@ -4019,6 +4018,7 @@ type Query { core_getManagedResouceOutputKeys(envName: String, msvcName: String, name: String!): [String!]! core_getManagedResouceOutputKeyValues(envName: String, keyrefs: [ManagedResourceKeyRefIn], msvcName: String): [ManagedResourceKeyValueRef!]! core_getManagedResource(envName: String, msvcName: String, name: String!): ManagedResource + core_getManagedServicePlugin(category: String!, name: String!): ManagedServicePlugin core_getRegistryImage(image: String!): RegistryImage core_getRegistryImageURL: RegistryImageURL! core_getRouter(envName: String!, name: String!): Router @@ -4035,6 +4035,7 @@ type Query { core_listImagePullSecrets(pq: CursorPaginationIn, search: SearchImagePullSecrets): ImagePullSecretPaginatedRecords core_listImportedManagedResources(envName: String!, pq: CursorPaginationIn, search: SearchImportedManagedResources): ImportedManagedResourcePaginatedRecords core_listManagedResources(pq: CursorPaginationIn, search: SearchManagedResources): ManagedResourcePaginatedRecords + core_listManagedServicePlugins: [ManagedServicePlugins!] core_listRegistryImages(pq: CursorPaginationIn): RegistryImagePaginatedRecords core_listRouters(envName: String!, pq: CursorPaginationIn, search: SearchRouters): RouterPaginatedRecords core_listSecrets(envName: String!, pq: CursorPaginationIn, search: SearchSecrets): SecretPaginatedRecords diff --git a/src/generated/gql/server.ts b/src/generated/gql/server.ts index 7bb49197e..268053e8a 100644 --- a/src/generated/gql/server.ts +++ b/src/generated/gql/server.ts @@ -5169,6 +5169,74 @@ export type ConsoleListMSvTemplatesQuery = { }>; }; +export type ConsoleGetMSvPluginQueryVariables = Exact<{ + category: Scalars['String']['input']; + name: Scalars['String']['input']; +}>; + +export type ConsoleGetMSvPluginQuery = { + core_getManagedServicePlugin?: { + plugin: string; + meta?: { logo: string }; + spec: { + apiVersion: string; + services: Array<{ + active: boolean; + description: string; + kind: string; + inputs: Array<{ + defaultValue?: any; + displayUnit?: string; + input: string; + label: string; + max?: number; + min?: number; + multiplier?: number; + required?: boolean; + type: string; + unit?: string; + }>; + resources: Array<{ description: string; kind: string }>; + }>; + }; + }; +}; + +export type ConsoleListMSvPluginsQueryVariables = Exact<{ + [key: string]: never; +}>; + +export type ConsoleListMSvPluginsQuery = { + core_listManagedServicePlugins?: Array<{ + category: string; + items: Array<{ + plugin: string; + meta?: { logo: string }; + spec: { + apiVersion: string; + services: Array<{ + active: boolean; + description: string; + kind: string; + inputs: Array<{ + defaultValue?: any; + displayUnit?: string; + input: string; + label: string; + max?: number; + min?: number; + multiplier?: number; + required?: boolean; + type: string; + unit?: string; + }>; + resources: Array<{ description: string; kind: string }>; + }>; + }; + }>; + }>; +}; + export type ConsoleGetManagedResourceQueryVariables = Exact<{ name: Scalars['String']['input']; msvcName?: InputMaybe;