From 669fbd6aa615f1a8c592bae8b8fc89ef88393884 Mon Sep 17 00:00:00 2001 From: Sayantan Mondal Date: Fri, 1 Aug 2025 10:49:43 +0000 Subject: [PATCH] feat: [CDE-898]: allowed image paths in admin settings (#4186) * refactor: restructure devcontainer image configuration with access list and image details * refactor: simplify image validation pattern and update error message for wildcard usage * refactor: extract image path cells into separate components and simplify form data merge * feat: [CDE-898]: allowed image paths in admin settings --- .../AllowedImagePaths.module.scss | 38 +++++ .../AllowedImagePaths.module.scss.d.ts | 23 +++ .../AllowedImagePaths/AllowedImagePaths.tsx | 129 ++++++++++++++++ .../DefaultGitspaceImage.module.scss | 2 +- .../DefaultGitspaceImage.tsx | 16 +- .../RegionAccordion/RegionAccordion.tsx | 3 +- .../components/RegionsPanel/RegionsPanel.tsx | 3 +- .../AdminSettings/AdminSettings.module.scss | 9 +- .../pages/AdminSettings/AdminSettings.tsx | 139 ++++++++---------- .../CloudRegions/CloudRegions.tsx | 7 +- .../GitspaceImages/GitspaceImages.tsx | 2 + .../AdminSettings/hooks/useAdminSettings.ts | 15 +- .../AdminSettings/utils/adminSettingsUtils.ts | 39 ++++- web/src/cde-gitness/strings/strings.en.yaml | 25 ++-- .../cde-gitness/utils/cloudRegionsUtils.ts | 13 +- .../ProvideDefaultImage.tsx | 22 +-- web/src/framework/strings/stringTypes.ts | 4 + web/src/i18n/strings.en.yaml | 3 + 18 files changed, 352 insertions(+), 140 deletions(-) create mode 100644 web/src/cde-gitness/components/AllowedImagePaths/AllowedImagePaths.module.scss create mode 100644 web/src/cde-gitness/components/AllowedImagePaths/AllowedImagePaths.module.scss.d.ts create mode 100644 web/src/cde-gitness/components/AllowedImagePaths/AllowedImagePaths.tsx diff --git a/web/src/cde-gitness/components/AllowedImagePaths/AllowedImagePaths.module.scss b/web/src/cde-gitness/components/AllowedImagePaths/AllowedImagePaths.module.scss new file mode 100644 index 000000000..68557e1ce --- /dev/null +++ b/web/src/cde-gitness/components/AllowedImagePaths/AllowedImagePaths.module.scss @@ -0,0 +1,38 @@ +.mainContentCard { + padding: var(--spacing-large); + margin: 0; + border-radius: var(--border-radius-medium); + box-shadow: 0 2px 8px rgba(96, 97, 112, 0.16); + width: 100%; + background: var(--white); +} + +.imagePathCard { + width: 100%; + margin: 0; +} + +.imagePathCellContainer { + min-height: 60px; +} + +.defaultImageTable { + :global { + .bp3-table { + border: none; + } + + .bp3-table-cell { + vertical-align: middle; + + &:last-child { + border-right: none; + } + } + } +} + +.defaultImageTableRow { + padding: 0 !important; + border-bottom: none !important; +} diff --git a/web/src/cde-gitness/components/AllowedImagePaths/AllowedImagePaths.module.scss.d.ts b/web/src/cde-gitness/components/AllowedImagePaths/AllowedImagePaths.module.scss.d.ts new file mode 100644 index 000000000..befc3184b --- /dev/null +++ b/web/src/cde-gitness/components/AllowedImagePaths/AllowedImagePaths.module.scss.d.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2023 Harness, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* eslint-disable */ +// This is an auto-generated file +export declare const defaultImageTable: string +export declare const defaultImageTableRow: string +export declare const imagePathCard: string +export declare const imagePathCellContainer: string +export declare const mainContentCard: string diff --git a/web/src/cde-gitness/components/AllowedImagePaths/AllowedImagePaths.tsx b/web/src/cde-gitness/components/AllowedImagePaths/AllowedImagePaths.tsx new file mode 100644 index 000000000..66f13809d --- /dev/null +++ b/web/src/cde-gitness/components/AllowedImagePaths/AllowedImagePaths.tsx @@ -0,0 +1,129 @@ +import React, { useMemo } from 'react' +import { Card, Text, Layout, Button, ButtonVariation, Container, TableV2, FormInput } from '@harnessio/uicore' +import { Color, FontVariation } from '@harnessio/design-system' +import { useFormikContext, FieldArray } from 'formik' +import type { Column } from 'react-table' +import { useStrings } from 'framework/strings' +import type { AdminSettingsFormValues } from 'cde-gitness/pages/AdminSettings/utils/adminSettingsUtils' +import css from './AllowedImagePaths.module.scss' + +interface ConnectorRowData { + imagePath: string +} + +interface CellRenderProps { + row: { index: number } + remove: (index: number) => void +} + +type CellRenderFunction = (props: CellRenderProps) => React.ReactNode + +type ColumnType = Column & { + Cell?: CellRenderFunction +} + +const ImagePathCell = React.memo(({ row }: Pick) => { + return ( + + + + ) +}) + +ImagePathCell.displayName = 'ImagePathCell' + +const DeleteCell = React.memo(({ row, remove }: CellRenderProps) => { + return ( + + + + )} + + + + ) +} diff --git a/web/src/cde-gitness/components/DefaultGitspaceImage/DefaultGitspaceImage.module.scss b/web/src/cde-gitness/components/DefaultGitspaceImage/DefaultGitspaceImage.module.scss index d7c3c026b..7e43d4d82 100644 --- a/web/src/cde-gitness/components/DefaultGitspaceImage/DefaultGitspaceImage.module.scss +++ b/web/src/cde-gitness/components/DefaultGitspaceImage/DefaultGitspaceImage.module.scss @@ -43,5 +43,5 @@ } .defaultImageTableRow { - padding: var(--spacing-large) var(--spacing-medium) var(--spacing-large) var(--spacing-large) !important; + padding: var(--spacing-large) var(--spacing-medium) var(--spacing-small) var(--spacing-medium) !important; } diff --git a/web/src/cde-gitness/components/DefaultGitspaceImage/DefaultGitspaceImage.tsx b/web/src/cde-gitness/components/DefaultGitspaceImage/DefaultGitspaceImage.tsx index bd8e96509..2e6f74b40 100644 --- a/web/src/cde-gitness/components/DefaultGitspaceImage/DefaultGitspaceImage.tsx +++ b/web/src/cde-gitness/components/DefaultGitspaceImage/DefaultGitspaceImage.tsx @@ -5,7 +5,7 @@ import { Color, FontVariation } from '@harnessio/design-system' import { useFormikContext } from 'formik' import { useStrings } from 'framework/strings' import { ProvideDefaultImageModal } from 'components/ProvideDefaultImage/ProvideDefaultImage' -import type { AdminSettingsFormValues } from 'cde-gitness/utils/cloudRegionsUtils' +import type { AdminSettingsFormValues } from 'cde-gitness/pages/AdminSettings/utils/adminSettingsUtils' import { useAppContext } from 'AppContext' import type { TypesGitspaceSettingsResponse } from 'services/cde' import { getConnectorIcon } from 'cde-gitness/pages/AdminSettings/utils/connectorUtils' @@ -16,11 +16,11 @@ interface DefaultGitspaceImageProps { } interface ConnectorRowData { - name?: string - identifier?: string - type?: string - id?: string - imagePath?: string + name: string + identifier: string + type: string + id: string + imagePath: string } interface TableRowProps { @@ -61,6 +61,7 @@ export const DefaultGitspaceImage: React.FC = ({ sett iconProps={{ size: 24 }} onClick={() => { setFieldValue('gitspaceImages', { + ...values.gitspaceImages, image_name: undefined, image_connector_ref: undefined, default_image_added: false @@ -70,7 +71,7 @@ export const DefaultGitspaceImage: React.FC = ({ sett /> ), - [setFieldValue] + [setFieldValue, values.gitspaceImages] ) const ImagePathCell = useCallback( @@ -194,7 +195,6 @@ export const DefaultGitspaceImage: React.FC = ({ sett setIsModalOpen(false) if (formValues?.imagePath) { setShowRow(true) - setFieldValue('gitspaceImages.default_image_added', true) } }} /> diff --git a/web/src/cde-gitness/components/RegionAccordion/RegionAccordion.tsx b/web/src/cde-gitness/components/RegionAccordion/RegionAccordion.tsx index 0140e351e..5ca72dbd9 100644 --- a/web/src/cde-gitness/components/RegionAccordion/RegionAccordion.tsx +++ b/web/src/cde-gitness/components/RegionAccordion/RegionAccordion.tsx @@ -4,7 +4,8 @@ import { Color, FontVariation } from '@harnessio/design-system' import { useFormikContext } from 'formik' import FlagsIcon from 'cde-gitness/assests/Flags.svg?url' import { useStrings } from 'framework/strings' -import type { RegionData, AdminSettingsFormValues } from 'cde-gitness/utils/cloudRegionsUtils' +import type { RegionData } from 'cde-gitness/utils/cloudRegionsUtils' +import type { AdminSettingsFormValues } from 'cde-gitness/pages/AdminSettings/utils/adminSettingsUtils' import MachineTypeCard from '../MachineTypeCard/MachineTypeCard' import css from './RegionAccordion.module.scss' diff --git a/web/src/cde-gitness/components/RegionsPanel/RegionsPanel.tsx b/web/src/cde-gitness/components/RegionsPanel/RegionsPanel.tsx index 8c905a138..21b9d97d7 100644 --- a/web/src/cde-gitness/components/RegionsPanel/RegionsPanel.tsx +++ b/web/src/cde-gitness/components/RegionsPanel/RegionsPanel.tsx @@ -3,8 +3,9 @@ import { Text, Layout, Container } from '@harnessio/uicore' import { Color, FontVariation } from '@harnessio/design-system' import { useFormikContext } from 'formik' import AWSIcon from 'cde-gitness/assests/aws.svg?url' -import type { InfraProviderResource, RegionData, AdminSettingsFormValues } from 'cde-gitness/utils/cloudRegionsUtils' +import type { InfraProviderResource, RegionData } from 'cde-gitness/utils/cloudRegionsUtils' import { useStrings } from 'framework/strings' +import type { AdminSettingsFormValues } from 'cde-gitness/pages/AdminSettings/utils/adminSettingsUtils' import GCPIcon from '../../../icons/google-cloud.svg?url' import HarnessIcon from '../../../icons/Harness.svg?url' import RegionAccordion from '../RegionAccordion/RegionAccordion' diff --git a/web/src/cde-gitness/pages/AdminSettings/AdminSettings.module.scss b/web/src/cde-gitness/pages/AdminSettings/AdminSettings.module.scss index c59efc357..a98b3b5ef 100644 --- a/web/src/cde-gitness/pages/AdminSettings/AdminSettings.module.scss +++ b/web/src/cde-gitness/pages/AdminSettings/AdminSettings.module.scss @@ -16,7 +16,7 @@ .tabContainer { width: 100% !important; - height: calc(var(--page-height) - var(--page-header-height, 64px)); + min-height: calc(var(--page-height) - var(--page-header-height, 64px)); display: flex; [class*='bp3-tab-list'] { @@ -25,10 +25,6 @@ padding: 0 var(--spacing-xlarge) !important; } - [class*='bp3-tab'] { - margin-right: 0 !important; - } - :global(.bp3-tabs) { display: flex; flex-direction: column; @@ -38,11 +34,10 @@ :global(.bp3-tab-panel) { flex-grow: 1; margin-top: 0; - padding: 0 !important; /* The panel should not have its own padding if the content inside handles it */ + padding: 0 !important; } } .tabContent { padding: var(--spacing-large); - min-height: 400px; } diff --git a/web/src/cde-gitness/pages/AdminSettings/AdminSettings.tsx b/web/src/cde-gitness/pages/AdminSettings/AdminSettings.tsx index 31491f82d..b5a1932ce 100644 --- a/web/src/cde-gitness/pages/AdminSettings/AdminSettings.tsx +++ b/web/src/cde-gitness/pages/AdminSettings/AdminSettings.tsx @@ -1,112 +1,99 @@ import React from 'react' import { - Breadcrumbs, - Container, - Heading, - Layout, Page, - Tabs, + Container, Button, ButtonVariation, + Tabs, + Layout, + Heading, + Breadcrumbs, PageError, Formik, FormikForm } from '@harnessio/uicore' import { FontVariation } from '@harnessio/design-system' -import * as Yup from 'yup' import { routes } from 'cde-gitness/RouteDefinitions' import { useAppContext } from 'AppContext' import { useStrings } from 'framework/strings' import { useAdminSettings } from './hooks/useAdminSettings' +import { getValidationSchema, AdminSettingsTabs } from './utils/adminSettingsUtils' import GitProviders from './GitProviders/GitProviders' import CodeEditors from './CodeEditors/CodeEditors' import CloudRegions from './CloudRegions/CloudRegions' import GitspaceImages from './GitspaceImages/GitspaceImages' import css from './AdminSettings.module.scss' -const AdminSettingsPage = () => { +const AdminSettingsPage: React.FC = () => { const { getString } = useStrings() const { accountInfo } = useAppContext() const { settings, tabs, initialValues, selectedTab, loading, errorSettings, handleSave, handleTabChange, refetch } = useAdminSettings() - const validationSchema = Yup.object({ - gitspaceImages: Yup.object({ - image_name: Yup.string().when('default_image_added', { - is: true, - then: (schema: Yup.StringSchema) => - schema.required(getString('validation.nameIsRequired')).trim().min(1, getString('validation.nameIsRequired')), - otherwise: (schema: Yup.StringSchema) => schema.notRequired() - }) - }).notRequired() - }) - return ( - {() => { - return ( - - - - {getString('cde.gitspaces')} - - - } - content={ - - - - } - breadcrumbs={ - + {() => ( + + + + {getString('cde.gitspaces')} + + + } + content={ + + + + } + breadcrumbs={ + + } + /> + + {errorSettings ? ( + refetch()} /> + ) : ( + + ({ + id: tab.id, + title: tab.title, + panel: ( + <> + {tab.id === AdminSettingsTabs.GIT_PROVIDERS && } + {tab.id === AdminSettingsTabs.CODE_EDITORS && } + {tab.id === AdminSettingsTabs.CLOUD_REGIONS && } + {tab.id === AdminSettingsTabs.GITSPACE_IMAGES && } + + ) + }))} /> - } - /> - - {errorSettings ? ( - refetch()} /> - ) : ( - - ({ - id: tab.id, - title: tab.title, - panel: ( - <> - {tab.id === 'gitProviders' && } - {tab.id === 'codeEditors' && } - {tab.id === 'cloudRegions' && } - {tab.id === 'gitspaceImages' && } - - ) - }))} - /> - - )} - - - ) - }} + + )} + + + )} ) } diff --git a/web/src/cde-gitness/pages/AdminSettings/CloudRegions/CloudRegions.tsx b/web/src/cde-gitness/pages/AdminSettings/CloudRegions/CloudRegions.tsx index 0392f92a7..2a7f78abc 100644 --- a/web/src/cde-gitness/pages/AdminSettings/CloudRegions/CloudRegions.tsx +++ b/web/src/cde-gitness/pages/AdminSettings/CloudRegions/CloudRegions.tsx @@ -5,11 +5,8 @@ import type { TypesGitspaceSettingsResponse } from 'services/cde' import InfraProviderPanel from 'cde-gitness/components/InfraProviderPanel/InfraProviderPanel' import RegionsPanel from 'cde-gitness/components/RegionsPanel/RegionsPanel' import { useInfraProviderResources } from 'cde-gitness/pages/AdminSettings/CloudRegions/hooks/useInfraProviderResources' -import { - AdminSettingsFormValues, - getCloudRegionFieldPath, - processInfraProviderDenyList -} from 'cde-gitness/utils/cloudRegionsUtils' +import { getCloudRegionFieldPath, processInfraProviderDenyList } from 'cde-gitness/utils/cloudRegionsUtils' +import type { AdminSettingsFormValues } from '../utils/adminSettingsUtils' import css from './CloudRegions.module.scss' interface CloudRegionsProps { diff --git a/web/src/cde-gitness/pages/AdminSettings/GitspaceImages/GitspaceImages.tsx b/web/src/cde-gitness/pages/AdminSettings/GitspaceImages/GitspaceImages.tsx index be52cd370..da269f24e 100644 --- a/web/src/cde-gitness/pages/AdminSettings/GitspaceImages/GitspaceImages.tsx +++ b/web/src/cde-gitness/pages/AdminSettings/GitspaceImages/GitspaceImages.tsx @@ -3,6 +3,7 @@ import { Text, Layout } from '@harnessio/uicore' import { Color, FontVariation } from '@harnessio/design-system' import { useStrings } from 'framework/strings' import { DefaultGitspaceImage } from 'cde-gitness/components/DefaultGitspaceImage/DefaultGitspaceImage' +import { AllowedImagePaths } from 'cde-gitness/components/AllowedImagePaths/AllowedImagePaths' import type { TypesGitspaceSettingsResponse } from 'services/cde' import css from './GitspaceImages.module.scss' @@ -23,6 +24,7 @@ const GitspaceImages: React.FC = ({ settings }: GitspaceIma + ) } diff --git a/web/src/cde-gitness/pages/AdminSettings/hooks/useAdminSettings.ts b/web/src/cde-gitness/pages/AdminSettings/hooks/useAdminSettings.ts index 274b7f91b..f3414b1d1 100644 --- a/web/src/cde-gitness/pages/AdminSettings/hooks/useAdminSettings.ts +++ b/web/src/cde-gitness/pages/AdminSettings/hooks/useAdminSettings.ts @@ -7,14 +7,15 @@ import { useAppContext } from 'AppContext' import { createInitialValues, buildAdminSettingsPayload, - type AdminSettingsFormValues + type AdminSettingsFormValues, + AdminSettingsTabs } from '../utils/adminSettingsUtils' export const useAdminSettings = () => { const { getString } = useStrings() const { showSuccess, showError } = useToaster() const { accountInfo } = useAppContext() - const [selectedTab, setSelectedTab] = useState('gitProviders') + const [selectedTab, setSelectedTab] = useState(AdminSettingsTabs.GIT_PROVIDERS) const { data: settings, @@ -31,10 +32,10 @@ export const useAdminSettings = () => { const tabs = useMemo( () => [ - { id: 'gitProviders', title: getString('cde.settings.gitProviders') }, - { id: 'codeEditors', title: getString('cde.settings.codeEditors') }, - { id: 'cloudRegions', title: getString('cde.settings.cloudRegionsAndMachineTypes') }, - { id: 'gitspaceImages', title: getString('cde.settings.gitspaceImages') } + { id: AdminSettingsTabs.GIT_PROVIDERS, title: getString('cde.settings.gitProviders') }, + { id: AdminSettingsTabs.CODE_EDITORS, title: getString('cde.settings.codeEditors') }, + { id: AdminSettingsTabs.CLOUD_REGIONS, title: getString('cde.settings.cloudRegionsAndMachineTypes') }, + { id: AdminSettingsTabs.GITSPACE_IMAGES, title: getString('cde.settings.gitspaceImages') } ], [getString] ) @@ -53,7 +54,7 @@ export const useAdminSettings = () => { } } - const handleTabChange = (tabId: string) => { + const handleTabChange = (tabId: AdminSettingsTabs) => { setSelectedTab(tabId) } diff --git a/web/src/cde-gitness/pages/AdminSettings/utils/adminSettingsUtils.ts b/web/src/cde-gitness/pages/AdminSettings/utils/adminSettingsUtils.ts index 0cde11846..0dd327529 100644 --- a/web/src/cde-gitness/pages/AdminSettings/utils/adminSettingsUtils.ts +++ b/web/src/cde-gitness/pages/AdminSettings/utils/adminSettingsUtils.ts @@ -1,3 +1,4 @@ +import * as Yup from 'yup' import type { TypesGitspaceSettingsData, TypesGitspaceSettingsResponse, @@ -10,6 +11,13 @@ import { getIDETypeOptions, type IDEOption } from 'cde-gitness/constants' import type { EnumInfraProviderType } from 'cde-gitness/services' import type { StringsMap } from 'framework/strings/stringTypes' +export enum AdminSettingsTabs { + GIT_PROVIDERS = 'gitProviders', + CODE_EDITORS = 'codeEditors', + CLOUD_REGIONS = 'cloudRegions', + GITSPACE_IMAGES = 'gitspaceImages' +} + export interface AdminSettingsFormValues { gitProviders: { [key: string]: boolean @@ -137,7 +145,12 @@ export const transformGitspaceImagesToPayload = (formValues: AdminSettingsFormVa return { devcontainer_image: { - ...formValues.gitspaceImages + access_list: { + mode: 'allow' as const, + list: formValues.gitspaceImages.access_list?.list || [] + }, + image_name: formValues.gitspaceImages.image_name, + image_connector_ref: formValues.gitspaceImages.image_connector_ref } } } @@ -164,3 +177,27 @@ export const buildAdminSettingsPayload = ( infra_provider: transformCloudRegionsToPayload(formValues, settings) } } + +const imagePattern = /^[^*]*\*?$/ + +export const getValidationSchema = (getString: (key: keyof StringsMap) => string) => { + return Yup.object({ + gitspaceImages: Yup.object({ + access_list: Yup.object({ + list: Yup.array() + .of( + Yup.string() + .required(getString('validation.imagePathIsRequired')) + .matches(imagePattern, getString('validation.invalidImage')) + ) + .notRequired() + }).notRequired(), + image_name: Yup.string().when('default_image_added', { + is: true, + then: (schema: Yup.StringSchema) => + schema.required(getString('validation.pathIsRequired')).trim().min(1, getString('validation.pathIsRequired')), + otherwise: (schema: Yup.StringSchema) => schema.notRequired() + }) + }).notRequired() + }) +} diff --git a/web/src/cde-gitness/strings/strings.en.yaml b/web/src/cde-gitness/strings/strings.en.yaml index ba56ce68a..e352a5c1b 100644 --- a/web/src/cde-gitness/strings/strings.en.yaml +++ b/web/src/cde-gitness/strings/strings.en.yaml @@ -102,7 +102,8 @@ settings: privateRegistryDescription: Use private registry with authenticated access selectImageRegistryConnector: Select Image Registry Connector selectConnector: -Select Connector- - imageRegistryOrPath: Image Registry or path + imageRegistryOrPath: Image Registry or Path + imagePath: Image Path apply: Apply cancel: Cancel allowedImagePathsAndRegistries: Allowed Image Paths and Registries @@ -330,17 +331,17 @@ create: infraProviderFailed: Gitspace Infrastructure creation failed machineCreateSuccess: Machine created successfully machineCreateFailed: Machine creation failed - gitprovider : Git Provider - scmEmpty : All SCM options are disabled - ideEmpty : All IDEs disabled - selectGitProvider : Select a Git Provider - githubOauthhelpertext1 : Please Configure the GitHub OAuth to connect to the repositories you have access - githubOauthhelpertext2 : Configure the OAuth in Profile - githubOauthhelpertext3 : Visit the User Profile Settings. - githubOauthhelpertext4 : Under OAuth section, select Github and connect - githubOauthhelpertext5 : After configuring return back to this page to connect the private repositories - ideNote : Your Gitspace will open in the selected IDE to code - selectIde : Select an IDE + gitprovider: Git Provider + scmEmpty: All SCM options are disabled + ideEmpty: All IDEs disabled + selectGitProvider: Select a Git Provider + githubOauthhelpertext1: Please Configure the GitHub OAuth to connect to the repositories you have access + githubOauthhelpertext2: Configure the OAuth in Profile + githubOauthhelpertext3: Visit the User Profile Settings. + githubOauthhelpertext4: Under OAuth section, select Github and connect + githubOauthhelpertext5: After configuring return back to this page to connect the private repositories + ideNote: Your Gitspace will open in the selected IDE to code + selectIde: Select an IDE subtext: Start Coding, no setup required. Dedicated cloud development environments with your favorite editor. importWarning: diff --git a/web/src/cde-gitness/utils/cloudRegionsUtils.ts b/web/src/cde-gitness/utils/cloudRegionsUtils.ts index a39cbee2c..8b5f49ee4 100644 --- a/web/src/cde-gitness/utils/cloudRegionsUtils.ts +++ b/web/src/cde-gitness/utils/cloudRegionsUtils.ts @@ -1,4 +1,4 @@ -import type { TypesDevcontainerImage, TypesGitspaceSettingsResponse } from 'services/cde' +import type { TypesGitspaceSettingsResponse } from 'services/cde' export interface MachineType { identifier: string @@ -24,17 +24,6 @@ export interface InfraProviderResource { regions: RegionData[] } -export interface AdminSettingsFormValues { - cloudRegions: { - [infraProvider: string]: { - [region: string]: { - [machineTypeId: string]: boolean - } - } - } - gitspaceImages?: TypesDevcontainerImage -} - export const getCloudRegionFieldPath = (infraProvider: string, region: string, machineTypeId: string): string => { return `cloudRegions.${infraProvider}.${region}.${machineTypeId}` } diff --git a/web/src/components/ProvideDefaultImage/ProvideDefaultImage.tsx b/web/src/components/ProvideDefaultImage/ProvideDefaultImage.tsx index a6a942542..b22bd381c 100644 --- a/web/src/components/ProvideDefaultImage/ProvideDefaultImage.tsx +++ b/web/src/components/ProvideDefaultImage/ProvideDefaultImage.tsx @@ -4,7 +4,7 @@ import { Button, ButtonVariation, Dialog, FormInput, Layout, Text, FormikForm, F import { Color, FontVariation } from '@harnessio/design-system' import { useFormikContext } from 'formik' import { useStrings } from 'framework/strings' -import type { AdminSettingsFormValues } from 'cde-gitness/utils/cloudRegionsUtils' +import type { AdminSettingsFormValues } from 'cde-gitness/pages/AdminSettings/utils/adminSettingsUtils' import { useAppContext } from 'AppContext' import { PublicPrivateRegistrySelect, @@ -26,12 +26,12 @@ interface ProvideDefaultImageModalProps { export const ProvideDefaultImageModal: React.FC = ({ isOpen, onClose }) => { const { getString } = useStrings() - const { setFieldValue } = useFormikContext() + const { values, setFieldValue } = useFormikContext() const { customComponents, accountInfo } = useAppContext() const { MultiTypeConnectorField } = customComponents const validationSchema = Yup.object({ - imagePath: Yup.string().required(getString('validation.nameIsRequired')), + imagePath: Yup.string().required(getString('validation.pathIsRequired')), connectorRef: Yup.mixed().when('accessType', { is: 'private', then: () => Yup.mixed().required(getString('validation.connectorRequired')), @@ -40,16 +40,20 @@ export const ProvideDefaultImageModal: React.FC = }) const handleApply = useCallback( - (values: ModalFormValues) => { + (modalValues: ModalFormValues) => { + const currentGitspaceImages = values.gitspaceImages || {} + const defaultImageData = { - image_name: values.imagePath, - image_connector_ref: values.connectorRef + ...currentGitspaceImages, + image_name: modalValues.imagePath, + image_connector_ref: modalValues.connectorRef, + default_image_added: true } setFieldValue('gitspaceImages', defaultImageData) - onClose(values) + onClose(modalValues) }, - [setFieldValue, onClose] + [setFieldValue, onClose, values.gitspaceImages] ) if (!isOpen) { @@ -108,7 +112,7 @@ export const ProvideDefaultImageModal: React.FC = - {getString('cde.settings.images.imageRegistryOrPath')} + {getString('cde.settings.images.imagePath')} diff --git a/web/src/framework/strings/stringTypes.ts b/web/src/framework/strings/stringTypes.ts index 7eb3862af..c88687035 100644 --- a/web/src/framework/strings/stringTypes.ts +++ b/web/src/framework/strings/stringTypes.ts @@ -1229,6 +1229,8 @@ export interface StringsMap { 'validation.expirationDateRequired': string 'validation.gitBranchNameInvalid': string 'validation.gitTagNameInvalid': string + 'validation.imagePathIsRequired': string + 'validation.invalidImage': string 'validation.key': string 'validation.nameInvalid': string 'validation.nameIsRequired': string @@ -1236,6 +1238,7 @@ export interface StringsMap { 'validation.nameTooLong': string 'validation.nameTooShort': string 'validation.newPasswordRequired': string + 'validation.pathIsRequired': string 'validation.repoNamePatternIsNotValid': string 'validation.spaceNamePatternIsNotValid': string 'validation.uidInvalid': string @@ -1657,6 +1660,7 @@ export interface StringsMap { 'cde.settings.images.defaultImageDescription': string 'cde.settings.images.defaultPathToPrivateGitspaceImagePath': string 'cde.settings.images.defaultPathToPublicGitspaceImagePath': string + 'cde.settings.images.imagePath': string 'cde.settings.images.imagePathPlaceholder': string 'cde.settings.images.imageRegistryOrPath': string 'cde.settings.images.manageGitspaceImages': string diff --git a/web/src/i18n/strings.en.yaml b/web/src/i18n/strings.en.yaml index f98548263..152f06004 100644 --- a/web/src/i18n/strings.en.yaml +++ b/web/src/i18n/strings.en.yaml @@ -146,6 +146,9 @@ validation: emailRequired: Email is required uidRequired: User ID is required nameIsRequired: Name is required + pathIsRequired: Path is required + imagePathIsRequired: Image path is required + invalidImage: "Invalid image expression: the wildcard character '*' can appear at most once and only at the end." connectorRequired: Connector is required expirationDateRequired: Expiration date is required newPasswordRequired: New password is a required field