mirror of
https://github.com/argoproj/argo-cd
synced 2026-04-21 17:07:16 +00:00
feat(ui): enable hydrator support in app create panel (#26485)
Signed-off-by: Jonathan Winters <wintersjonathan0@gmail.com> Co-authored-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
This commit is contained in:
parent
8c1a815b78
commit
ff45972ec8
4 changed files with 393 additions and 187 deletions
|
|
@ -3,14 +3,16 @@ import {AutocompleteField, Checkbox, DataLoader, DropDownMenu, FormField, HelpIc
|
|||
import * as deepMerge from 'deepmerge';
|
||||
import * as React from 'react';
|
||||
import {FieldApi, Form, FormApi, FormField as ReactFormField, Text} from 'react-form';
|
||||
import {RevisionHelpIcon, YamlEditor} from '../../../shared/components';
|
||||
import {YamlEditor} from '../../../shared/components';
|
||||
import * as models from '../../../shared/models';
|
||||
import {services} from '../../../shared/services';
|
||||
import {AuthSettingsCtx} from '../../../shared/context';
|
||||
import {ApplicationParameters} from '../application-parameters/application-parameters';
|
||||
import {ApplicationRetryOptions} from '../application-retry-options/application-retry-options';
|
||||
import {ApplicationSyncOptionsField} from '../application-sync-options/application-sync-options';
|
||||
import {RevisionFormField} from '../revision-form-field/revision-form-field';
|
||||
import {SetFinalizerOnApplication} from './set-finalizer-on-application';
|
||||
import {HydratorSourcePanel} from './hydrator-source-panel';
|
||||
import {SourcePanel} from './source-panel';
|
||||
import './application-create-panel.scss';
|
||||
import {getAppDefaultSource} from '../utils';
|
||||
import {debounce} from 'lodash-es';
|
||||
|
|
@ -120,7 +122,10 @@ export const ApplicationCreatePanel = (props: {
|
|||
const currentRepoType = React.useRef(undefined);
|
||||
const lastGitOrHelmUrl = React.useRef('');
|
||||
const lastOciUrl = React.useRef('');
|
||||
const [isHydratorEnabled, setIsHydratorEnabled] = React.useState(!!app.spec.sourceHydrator);
|
||||
const [savedSyncSource, setSavedSyncSource] = React.useState(app.spec.sourceHydrator?.syncSource || {targetBranch: '', path: ''});
|
||||
let destinationComboValue = destinationFieldChanges.destFormat;
|
||||
const authSettingsCtx = React.useContext(AuthSettingsCtx);
|
||||
|
||||
React.useEffect(() => {
|
||||
comboSwitchedFromPanel.current = false;
|
||||
|
|
@ -184,6 +189,10 @@ export const ApplicationCreatePanel = (props: {
|
|||
delete data.spec.destination.server;
|
||||
}
|
||||
|
||||
if (data.spec.sourceHydrator && !data.spec.sourceHydrator.hydrateTo?.targetBranch) {
|
||||
delete data.spec.sourceHydrator.hydrateTo;
|
||||
}
|
||||
|
||||
props.createApp(data);
|
||||
};
|
||||
|
||||
|
|
@ -219,20 +228,29 @@ export const ApplicationCreatePanel = (props: {
|
|||
/>
|
||||
)) || (
|
||||
<Form
|
||||
validateError={(a: models.Application) => ({
|
||||
'metadata.name': !a.metadata.name && 'Application Name is required',
|
||||
'spec.project': !a.spec.project && 'Project Name is required',
|
||||
'spec.source.repoURL': !a.spec.source.repoURL && 'Repository URL is required',
|
||||
'spec.source.targetRevision': !a.spec.source.targetRevision && a.spec.source.hasOwnProperty('chart') && 'Version is required',
|
||||
'spec.source.path': !a.spec.source.path && !a.spec.source.chart && 'Path is required',
|
||||
'spec.source.chart': !a.spec.source.path && !a.spec.source.chart && 'Chart is required',
|
||||
// Verify cluster URL when there is no cluster name field or the name value is empty
|
||||
'spec.destination.server':
|
||||
!a.spec.destination.server && (!a.spec.destination.hasOwnProperty('name') || a.spec.destination.name === '') && 'Cluster URL is required',
|
||||
// Verify cluster name when there is no cluster URL field or the URL value is empty
|
||||
'spec.destination.name':
|
||||
!a.spec.destination.name && (!a.spec.destination.hasOwnProperty('server') || a.spec.destination.server === '') && 'Cluster name is required'
|
||||
})}
|
||||
validateError={(a: models.Application) => {
|
||||
const hasHydrator = !!a.spec.sourceHydrator;
|
||||
const source = a.spec.source;
|
||||
|
||||
return {
|
||||
'metadata.name': !a.metadata.name && 'Application Name is required',
|
||||
'spec.project': !a.spec.project && 'Project Name is required',
|
||||
'spec.source.repoURL': !hasHydrator && !source?.repoURL && 'Repository URL is required',
|
||||
'spec.source.targetRevision': !hasHydrator && !source?.targetRevision && source?.hasOwnProperty('chart') && 'Version is required',
|
||||
'spec.source.path': !hasHydrator && !source?.path && !source?.chart && 'Path is required',
|
||||
'spec.source.chart': !hasHydrator && !source?.path && !source?.chart && 'Chart is required',
|
||||
// Verify cluster URL when there is no cluster name field or the name value is empty
|
||||
'spec.destination.server':
|
||||
!a.spec.destination.server &&
|
||||
(!a.spec.destination.hasOwnProperty('name') || a.spec.destination.name === '') &&
|
||||
'Cluster URL is required',
|
||||
// Verify cluster name when there is no cluster URL field or the URL value is empty
|
||||
'spec.destination.name':
|
||||
!a.spec.destination.name &&
|
||||
(!a.spec.destination.hasOwnProperty('server') || a.spec.destination.server === '') &&
|
||||
'Cluster name is required'
|
||||
};
|
||||
}}
|
||||
defaultValues={app}
|
||||
formDidUpdate={state => debouncedOnAppChanged(state.values as any)}
|
||||
onSubmit={onCreateApp}
|
||||
|
|
@ -298,184 +316,57 @@ export const ApplicationCreatePanel = (props: {
|
|||
</div>
|
||||
);
|
||||
|
||||
const repoType = api.getFormState().values.spec.source.repoURL.startsWith('oci://')
|
||||
? 'oci'
|
||||
: (api.getFormState().values.spec.source.hasOwnProperty('chart') && 'helm') || 'git';
|
||||
const sourcePanel = () => (
|
||||
<div className='white-box'>
|
||||
<p>SOURCE</p>
|
||||
<div className='row argo-form-row'>
|
||||
<div className='columns small-10'>
|
||||
<FormField
|
||||
formApi={api}
|
||||
label='Repository URL'
|
||||
qeId='application-create-field-repository-url'
|
||||
field='spec.source.repoURL'
|
||||
component={AutocompleteField}
|
||||
componentProps={{
|
||||
items: repos,
|
||||
filterSuggestions: true
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className='columns small-2'>
|
||||
<div style={{paddingTop: '1.5em'}}>
|
||||
{(repoInfo && (
|
||||
<React.Fragment>
|
||||
<span>{(repoInfo.type || 'git').toUpperCase()}</span> <i className='fa fa-check' />
|
||||
</React.Fragment>
|
||||
)) || (
|
||||
<DropDownMenu
|
||||
anchor={() => (
|
||||
<p>
|
||||
{repoType.toUpperCase()} <i className='fa fa-caret-down' />
|
||||
</p>
|
||||
)}
|
||||
qeId='application-create-dropdown-source-repository'
|
||||
items={['git', 'helm', 'oci'].map((type: 'git' | 'helm' | 'oci') => ({
|
||||
title: type.toUpperCase(),
|
||||
action: () => {
|
||||
if (repoType !== type) {
|
||||
const updatedApp = api.getFormState().values as models.Application;
|
||||
const source = getAppDefaultSource(updatedApp);
|
||||
// Save the previous URL value for later use
|
||||
if (repoType === 'git' || repoType === 'helm') {
|
||||
lastGitOrHelmUrl.current = source.repoURL;
|
||||
} else {
|
||||
lastOciUrl.current = source.repoURL;
|
||||
}
|
||||
currentRepoType.current = type;
|
||||
switch (type) {
|
||||
case 'git':
|
||||
case 'oci':
|
||||
if (source.hasOwnProperty('chart')) {
|
||||
source.path = source.chart;
|
||||
delete source.chart;
|
||||
}
|
||||
source.targetRevision = 'HEAD';
|
||||
source.repoURL =
|
||||
type === 'git'
|
||||
? lastGitOrHelmUrl.current
|
||||
: lastOciUrl.current === ''
|
||||
? 'oci://'
|
||||
: lastOciUrl.current;
|
||||
break;
|
||||
case 'helm':
|
||||
if (source.hasOwnProperty('path')) {
|
||||
source.chart = source.path;
|
||||
delete source.path;
|
||||
}
|
||||
source.targetRevision = '';
|
||||
source.repoURL = lastGitOrHelmUrl.current;
|
||||
break;
|
||||
}
|
||||
api.setAllValues(updatedApp);
|
||||
{/* Only show hydrator checkbox if hydrator is enabled in auth settings */}
|
||||
{authSettingsCtx?.hydratorEnabled && (
|
||||
<div className='row argo-form-row'>
|
||||
<div className='columns small-12'>
|
||||
<div className='checkbox-container'>
|
||||
<Checkbox
|
||||
onChange={(val: boolean) => {
|
||||
const updatedApp = api.getFormState().values as models.Application;
|
||||
if (val) {
|
||||
if (!updatedApp.spec.sourceHydrator) {
|
||||
updatedApp.spec.sourceHydrator = {
|
||||
drySource: {
|
||||
repoURL: updatedApp.spec.source.repoURL,
|
||||
targetRevision: updatedApp.spec.source.targetRevision,
|
||||
path: updatedApp.spec.source.path
|
||||
},
|
||||
syncSource: savedSyncSource
|
||||
};
|
||||
delete updatedApp.spec.source;
|
||||
}
|
||||
} else if (updatedApp.spec.sourceHydrator) {
|
||||
setSavedSyncSource(updatedApp.spec.sourceHydrator.syncSource);
|
||||
updatedApp.spec.source = updatedApp.spec.sourceHydrator.drySource;
|
||||
delete updatedApp.spec.sourceHydrator;
|
||||
}
|
||||
}))}
|
||||
api.setAllValues(updatedApp);
|
||||
setIsHydratorEnabled(val);
|
||||
}}
|
||||
checked={!!(api.getFormState().values as models.Application).spec.sourceHydrator}
|
||||
id='enable-source-hydrator'
|
||||
/>
|
||||
)}
|
||||
<label htmlFor='enable-source-hydrator'>enable source hydrator</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{(repoType === 'oci' && (
|
||||
<React.Fragment>
|
||||
<RevisionFormField formApi={api} helpIconTop={'2.5em'} repoURL={app.spec.source.repoURL} repoType={repoType} />
|
||||
<div className='argo-form-row'>
|
||||
<DataLoader
|
||||
input={{repoURL: app.spec.source.repoURL, revision: app.spec.source.targetRevision}}
|
||||
load={async src =>
|
||||
src.repoURL &&
|
||||
// TODO: for autocomplete we need to fetch paths that are used by other apps within the same project making use of the same OCI repo
|
||||
new Array<string>()
|
||||
}>
|
||||
{(paths: string[]) => (
|
||||
<FormField
|
||||
formApi={api}
|
||||
label='Path'
|
||||
qeId='application-create-field-path'
|
||||
field='spec.source.path'
|
||||
component={AutocompleteField}
|
||||
componentProps={{
|
||||
items: paths,
|
||||
filterSuggestions: true
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</DataLoader>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)) ||
|
||||
(repoType === 'git' && (
|
||||
<React.Fragment>
|
||||
<RevisionFormField formApi={api} helpIconTop={'2.5em'} repoURL={app.spec.source.repoURL} repoType={repoType} />
|
||||
<div className='argo-form-row'>
|
||||
<DataLoader
|
||||
input={{repoURL: app.spec.source.repoURL, revision: app.spec.source.targetRevision}}
|
||||
load={async src =>
|
||||
(src.repoURL &&
|
||||
services.repos
|
||||
.apps(src.repoURL, src.revision, app.metadata.name, app.spec.project)
|
||||
.then(apps => Array.from(new Set(apps.map(item => item.path))).sort())
|
||||
.catch(() => new Array<string>())) ||
|
||||
new Array<string>()
|
||||
}>
|
||||
{(apps: string[]) => (
|
||||
<FormField
|
||||
formApi={api}
|
||||
label='Path'
|
||||
qeId='application-create-field-path'
|
||||
field='spec.source.path'
|
||||
component={AutocompleteField}
|
||||
componentProps={{
|
||||
items: apps,
|
||||
filterSuggestions: true
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</DataLoader>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)) || (
|
||||
<DataLoader
|
||||
input={{repoURL: app.spec.source.repoURL}}
|
||||
load={async src =>
|
||||
(src.repoURL && services.repos.charts(src.repoURL).catch(() => new Array<models.HelmChart>())) ||
|
||||
new Array<models.HelmChart>()
|
||||
}>
|
||||
{(charts: models.HelmChart[]) => {
|
||||
const selectedChart = charts.find(chart => chart.name === api.getFormState().values.spec.source.chart);
|
||||
return (
|
||||
<div className='row argo-form-row'>
|
||||
<div className='columns small-10'>
|
||||
<FormField
|
||||
formApi={api}
|
||||
label='Chart'
|
||||
field='spec.source.chart'
|
||||
component={AutocompleteField}
|
||||
componentProps={{
|
||||
items: charts.map(chart => chart.name),
|
||||
filterSuggestions: true
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className='columns small-2'>
|
||||
<FormField
|
||||
formApi={api}
|
||||
field='spec.source.targetRevision'
|
||||
component={AutocompleteField}
|
||||
componentProps={{
|
||||
items: (selectedChart && selectedChart.versions) || [],
|
||||
filterSuggestions: true
|
||||
}}
|
||||
/>
|
||||
<RevisionHelpIcon type='helm' />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</DataLoader>
|
||||
)}
|
||||
)}
|
||||
{isHydratorEnabled ? (
|
||||
<HydratorSourcePanel formApi={api} repos={repos} />
|
||||
) : (
|
||||
<SourcePanel
|
||||
formApi={api}
|
||||
repos={repos}
|
||||
repoInfo={repoInfo}
|
||||
currentRepoType={currentRepoType}
|
||||
lastGitOrHelmUrl={lastGitOrHelmUrl}
|
||||
lastOciUrl={lastOciUrl}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
const destinationPanel = () => (
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
import * as React from 'react';
|
||||
import {FormApi, Text} from 'react-form';
|
||||
import {AutocompleteField, FormField} from 'argo-ui';
|
||||
|
||||
import * as models from '../../../shared/models';
|
||||
import {RevisionFormField} from '../revision-form-field/revision-form-field';
|
||||
|
||||
interface HydratorSourcePanelProps {
|
||||
formApi: FormApi;
|
||||
repos: string[];
|
||||
}
|
||||
|
||||
interface LabeledRevisionFieldProps {
|
||||
formApi: FormApi;
|
||||
repoURL: string;
|
||||
fieldValue: string;
|
||||
repoType?: string;
|
||||
revisionType?: 'Branches' | 'Tags';
|
||||
helpIconTop?: string;
|
||||
compact?: boolean;
|
||||
}
|
||||
|
||||
const LabeledRevisionField = (props: LabeledRevisionFieldProps) => (
|
||||
<div style={{display: 'flex', width: '100%'}}>
|
||||
<div style={{flex: 1, minWidth: 0}}>
|
||||
<RevisionFormField
|
||||
formApi={props.formApi}
|
||||
helpIconTop={props.helpIconTop}
|
||||
repoURL={props.repoURL}
|
||||
repoType={props.repoType}
|
||||
fieldValue={props.fieldValue}
|
||||
revisionType={props.revisionType}
|
||||
compact={props.compact !== false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const subsectionBodyStyle: React.CSSProperties = {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '2.5rem',
|
||||
paddingLeft: '0.75rem',
|
||||
borderLeft: '2px solid #e2e5e9'
|
||||
};
|
||||
|
||||
export const HydratorSourcePanel = (props: HydratorSourcePanelProps) => {
|
||||
const app = props.formApi.getFormState().values as models.Application;
|
||||
const drySourceRepoURL = app.spec.sourceHydrator?.drySource?.repoURL || '';
|
||||
|
||||
return (
|
||||
<div style={{display: 'flex', flexDirection: 'column', gap: '1rem'}}>
|
||||
<div style={{display: 'flex', flexDirection: 'column'}}>
|
||||
<p style={{marginBottom: 0, fontWeight: 600}}>DRY SOURCE</p>
|
||||
<div style={subsectionBodyStyle}>
|
||||
<div style={{display: 'flex', width: '100%'}}>
|
||||
<div style={{flex: 1, minWidth: 0}}>
|
||||
<FormField
|
||||
formApi={props.formApi}
|
||||
label='Repository URL'
|
||||
field='spec.sourceHydrator.drySource.repoURL'
|
||||
component={AutocompleteField}
|
||||
componentProps={{
|
||||
items: props.repos,
|
||||
filterSuggestions: true
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<LabeledRevisionField
|
||||
formApi={props.formApi}
|
||||
repoURL={drySourceRepoURL}
|
||||
repoType='git'
|
||||
fieldValue='spec.sourceHydrator.drySource.targetRevision'
|
||||
helpIconTop='2.5em'
|
||||
/>
|
||||
<div style={{display: 'flex', width: '100%'}}>
|
||||
<div style={{flex: 1, minWidth: 0}}>
|
||||
<FormField formApi={props.formApi} label='Path' field='spec.sourceHydrator.drySource.path' component={Text} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{display: 'flex', flexDirection: 'column'}}>
|
||||
<p style={{marginBottom: 0, fontWeight: 600}}>SYNC SOURCE</p>
|
||||
<div style={subsectionBodyStyle}>
|
||||
<LabeledRevisionField
|
||||
formApi={props.formApi}
|
||||
repoURL={drySourceRepoURL}
|
||||
repoType='git'
|
||||
fieldValue='spec.sourceHydrator.syncSource.targetBranch'
|
||||
revisionType='Branches'
|
||||
/>
|
||||
<div style={{display: 'flex', width: '100%'}}>
|
||||
<div style={{flex: 1, minWidth: 0}}>
|
||||
<FormField formApi={props.formApi} label='Path' field='spec.sourceHydrator.syncSource.path' component={Text} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{display: 'flex', flexDirection: 'column', gap: '0.5rem'}}>
|
||||
<p style={{fontWeight: 600}}>HYDRATE TO</p>
|
||||
<div style={subsectionBodyStyle}>
|
||||
<LabeledRevisionField
|
||||
formApi={props.formApi}
|
||||
repoURL={drySourceRepoURL}
|
||||
repoType='git'
|
||||
fieldValue='spec.sourceHydrator.hydrateTo.targetBranch'
|
||||
revisionType='Branches'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
import {AutocompleteField, DataLoader, DropDownMenu, FormField} from 'argo-ui';
|
||||
import * as React from 'react';
|
||||
import {FormApi} from 'react-form';
|
||||
import {RevisionHelpIcon} from '../../../shared/components';
|
||||
import * as models from '../../../shared/models';
|
||||
import {services} from '../../../shared/services';
|
||||
import {RevisionFormField} from '../revision-form-field/revision-form-field';
|
||||
import {getAppDefaultSource} from '../utils';
|
||||
|
||||
interface SourcePanelProps {
|
||||
formApi: FormApi;
|
||||
repos: string[];
|
||||
repoInfo?: models.Repository;
|
||||
currentRepoType: React.MutableRefObject<string>;
|
||||
lastGitOrHelmUrl: React.MutableRefObject<string>;
|
||||
lastOciUrl: React.MutableRefObject<string>;
|
||||
}
|
||||
|
||||
export const SourcePanel = (props: SourcePanelProps) => {
|
||||
const currentApp = props.formApi.getFormState().values as models.Application;
|
||||
const currentSource = getAppDefaultSource(currentApp);
|
||||
const repoType = currentSource?.repoURL?.startsWith('oci://') ? 'oci' : (currentSource && Object.prototype.hasOwnProperty.call(currentSource, 'chart') && 'helm') || 'git';
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div style={{display: 'flex', alignItems: 'flex-start'}}>
|
||||
<div style={{flex: '1 1 auto', minWidth: 0}}>
|
||||
<FormField
|
||||
formApi={props.formApi}
|
||||
label='Repository URL'
|
||||
qeId='application-create-field-repository-url'
|
||||
field='spec.source.repoURL'
|
||||
component={AutocompleteField}
|
||||
componentProps={{
|
||||
items: props.repos,
|
||||
filterSuggestions: true
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div style={{flex: '0 0 auto', minWidth: '7rem'}}>
|
||||
<div style={{paddingTop: '1.5em'}}>
|
||||
{(props.repoInfo && (
|
||||
<React.Fragment>
|
||||
<span>{(props.repoInfo.type || 'git').toUpperCase()}</span> <i className='fa fa-check' />
|
||||
</React.Fragment>
|
||||
)) || (
|
||||
<DropDownMenu
|
||||
anchor={() => (
|
||||
<p>
|
||||
{repoType.toUpperCase()} <i className='fa fa-caret-down' />
|
||||
</p>
|
||||
)}
|
||||
qeId='application-create-dropdown-source-repository'
|
||||
items={['git', 'helm', 'oci'].map((type: 'git' | 'helm' | 'oci') => ({
|
||||
title: type.toUpperCase(),
|
||||
action: () => {
|
||||
if (repoType !== type) {
|
||||
const updatedApp = props.formApi.getFormState().values as models.Application;
|
||||
const source = getAppDefaultSource(updatedApp);
|
||||
// Save the previous URL value for later use
|
||||
if (repoType === 'git' || repoType === 'helm') {
|
||||
props.lastGitOrHelmUrl.current = source.repoURL;
|
||||
} else {
|
||||
props.lastOciUrl.current = source.repoURL;
|
||||
}
|
||||
props.currentRepoType.current = type;
|
||||
switch (type) {
|
||||
case 'git':
|
||||
case 'oci':
|
||||
if (Object.prototype.hasOwnProperty.call(source, 'chart')) {
|
||||
source.path = source.chart;
|
||||
delete source.chart;
|
||||
}
|
||||
source.targetRevision = 'HEAD';
|
||||
source.repoURL =
|
||||
type === 'git' ? props.lastGitOrHelmUrl.current : props.lastOciUrl.current === '' ? 'oci://' : props.lastOciUrl.current;
|
||||
break;
|
||||
case 'helm':
|
||||
if (Object.prototype.hasOwnProperty.call(source, 'path')) {
|
||||
source.chart = source.path;
|
||||
delete source.path;
|
||||
}
|
||||
source.targetRevision = '';
|
||||
source.repoURL = props.lastGitOrHelmUrl.current;
|
||||
break;
|
||||
}
|
||||
props.formApi.setAllValues(updatedApp);
|
||||
}
|
||||
}
|
||||
}))}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{(repoType === 'oci' && (
|
||||
<React.Fragment>
|
||||
<RevisionFormField formApi={props.formApi} helpIconTop={'2.5em'} repoURL={currentApp.spec.source.repoURL} repoType={repoType} />
|
||||
<div className='argo-form-row'>
|
||||
<DataLoader
|
||||
input={{repoURL: currentApp.spec.source.repoURL, revision: currentApp.spec.source.targetRevision}}
|
||||
load={async src =>
|
||||
src.repoURL &&
|
||||
// TODO: for autocomplete we need to fetch paths that are used by other apps within the same project making use of the same OCI repo
|
||||
new Array<string>()
|
||||
}>
|
||||
{(paths: string[]) => (
|
||||
<FormField
|
||||
formApi={props.formApi}
|
||||
label='Path'
|
||||
qeId='application-create-field-path'
|
||||
field='spec.source.path'
|
||||
component={AutocompleteField}
|
||||
componentProps={{
|
||||
items: paths,
|
||||
filterSuggestions: true
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</DataLoader>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)) ||
|
||||
(repoType === 'git' && (
|
||||
<React.Fragment>
|
||||
<RevisionFormField formApi={props.formApi} helpIconTop={'2.5em'} repoURL={currentApp.spec.source.repoURL} repoType={repoType} />
|
||||
<div className='argo-form-row'>
|
||||
<DataLoader
|
||||
input={{repoURL: currentApp.spec.source.repoURL, revision: currentApp.spec.source.targetRevision}}
|
||||
load={async src =>
|
||||
(src.repoURL &&
|
||||
services.repos
|
||||
.apps(src.repoURL, src.revision, currentApp.metadata.name, currentApp.spec.project)
|
||||
.then(apps => Array.from(new Set(apps.map(item => item.path))).sort())
|
||||
.catch(() => new Array<string>())) ||
|
||||
new Array<string>()
|
||||
}>
|
||||
{(apps: string[]) => (
|
||||
<FormField
|
||||
formApi={props.formApi}
|
||||
label='Path'
|
||||
qeId='application-create-field-path'
|
||||
field='spec.source.path'
|
||||
component={AutocompleteField}
|
||||
componentProps={{
|
||||
items: apps,
|
||||
filterSuggestions: true
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</DataLoader>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)) || (
|
||||
<DataLoader
|
||||
input={{repoURL: currentApp.spec.source.repoURL}}
|
||||
load={async src => (src.repoURL && services.repos.charts(src.repoURL).catch(() => new Array<models.HelmChart>())) || new Array<models.HelmChart>()}>
|
||||
{(charts: models.HelmChart[]) => {
|
||||
const selectedChart = charts.find(chart => chart.name === props.formApi.getFormState().values.spec.source.chart);
|
||||
return (
|
||||
<div className='row argo-form-row'>
|
||||
<div className='columns small-10'>
|
||||
<FormField
|
||||
formApi={props.formApi}
|
||||
label='Chart'
|
||||
field='spec.source.chart'
|
||||
component={AutocompleteField}
|
||||
componentProps={{
|
||||
items: charts.map(chart => chart.name),
|
||||
filterSuggestions: true
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className='columns small-2'>
|
||||
<FormField
|
||||
formApi={props.formApi}
|
||||
field='spec.source.targetRevision'
|
||||
component={AutocompleteField}
|
||||
componentProps={{
|
||||
items: (selectedChart && selectedChart.versions) || [],
|
||||
filterSuggestions: true
|
||||
}}
|
||||
/>
|
||||
<RevisionHelpIcon type='helm' />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</DataLoader>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
|
@ -11,6 +11,7 @@ interface RevisionFormFieldProps {
|
|||
formApi: FormApi;
|
||||
helpIconTop?: string;
|
||||
hideLabel?: boolean;
|
||||
compact?: boolean;
|
||||
repoURL: string;
|
||||
fieldValue?: string;
|
||||
repoType?: string;
|
||||
|
|
@ -27,8 +28,13 @@ export function RevisionFormField(props: RevisionFormFieldProps) {
|
|||
const selectedFilter = props.revisionType || filterType;
|
||||
const rowClass = props.hideLabel ? '' : ' argo-form-row';
|
||||
const rowPaddingRight = !props.revisionType ? '45px' : undefined;
|
||||
const wrapperClassName = [props.compact ? '' : 'row' + rowClass, 'revision-form-field'].filter(Boolean).join(' ');
|
||||
const wrapperStyle: React.CSSProperties = {
|
||||
paddingRight: rowPaddingRight,
|
||||
...(props.compact ? {marginTop: 0, marginBottom: 0} : {})
|
||||
};
|
||||
return (
|
||||
<div className={'row' + rowClass + ' revision-form-field'} style={{paddingRight: rowPaddingRight}}>
|
||||
<div className={wrapperClassName} style={wrapperStyle}>
|
||||
<div className='revision-form-field__main'>
|
||||
<DataLoader
|
||||
input={{repoURL: props.repoURL, filterType: selectedFilter}}
|
||||
|
|
|
|||
Loading…
Reference in a new issue