mirror of
https://github.com/argoproj/argo-cd
synced 2026-05-24 09:50:08 +00:00
parent
9df130938e
commit
c3479b886a
7 changed files with 79 additions and 12 deletions
|
|
@ -131,7 +131,7 @@ export const ApplicationCreatePanel = (props: {
|
|||
'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 && 'Revision 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',
|
||||
'spec.destination.server': !a.spec.destination.server && 'Cluster is required',
|
||||
|
|
|
|||
|
|
@ -43,4 +43,19 @@
|
|||
border: 1px solid #dbdcdc;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.argo-field {
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
.white-box__details-row .row {
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
.white-box__details-row .row .columns:last-child {
|
||||
padding-left: 1em;
|
||||
}
|
||||
.select {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { FormApi, Text } from 'react-form';
|
|||
|
||||
require('./application-summary.scss');
|
||||
|
||||
import { Cluster, clusterTitle, DataLoader, EditablePanel, EditablePanelItem } from '../../../shared/components';
|
||||
import { AutocompleteField, Cluster, clusterTitle, DataLoader, EditablePanel, EditablePanelItem } from '../../../shared/components';
|
||||
import { Repo, Revision } from '../../../shared/components';
|
||||
import { Consumer } from '../../../shared/context';
|
||||
import * as models from '../../../shared/models';
|
||||
|
|
@ -26,6 +26,7 @@ export const ApplicationSummary = (props: {
|
|||
updateApp: (app: models.Application) => Promise<any>,
|
||||
}) => {
|
||||
const app = JSON.parse(JSON.stringify(props.app)) as models.Application;
|
||||
const isHelm = app.spec.source.hasOwnProperty('chart');
|
||||
|
||||
const attributes = [
|
||||
{
|
||||
|
|
@ -63,16 +64,43 @@ export const ApplicationSummary = (props: {
|
|||
view: <Repo url={app.spec.source.repoURL}/>,
|
||||
edit: (formApi: FormApi) => <FormField formApi={formApi} field='spec.source.repoURL' component={Text}/>,
|
||||
},
|
||||
{
|
||||
...(isHelm ? [{
|
||||
title: 'CHART',
|
||||
view: <span>{app.spec.source.chart}:{app.spec.source.targetRevision}</span>,
|
||||
edit: (formApi: FormApi) => (
|
||||
<DataLoader input={{repoURL: formApi.getFormState().values.spec.source.repoURL, chart: formApi.getFormState().values.spec.source.chart}}
|
||||
load={(src) => services.repos.charts(src.repoURL).catch(() => new Array<models.HelmChart>()).then((charts) => {
|
||||
const chartInfo = charts.find((chart) => chart.name === src.chart);
|
||||
return {
|
||||
charts: charts.map((chart) => chart.name),
|
||||
versions: chartInfo && chartInfo.versions || new Array<string>(),
|
||||
};
|
||||
})}>
|
||||
{(data: {charts: string[], versions: string[] }) => (
|
||||
<div className='row'>
|
||||
<div className='columns small-10'>
|
||||
<FormField formApi={formApi} field='spec.source.chart' component={AutocompleteField} componentProps={{
|
||||
items: data.charts, filterSuggestions: true,
|
||||
}}/>
|
||||
</div>
|
||||
<div className='columns small-2'>
|
||||
<FormField formApi={formApi} field='spec.source.targetRevision' component={AutocompleteField} componentProps={{
|
||||
items: data.versions,
|
||||
}}/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</DataLoader>
|
||||
),
|
||||
}] : [{
|
||||
title: 'TARGET REVISION',
|
||||
view: <Revision repoUrl={app.spec.source.repoURL} revision={app.spec.source.targetRevision}/>,
|
||||
edit: (formApi: FormApi) => <FormField formApi={formApi} field='spec.source.targetRevision' component={Text}/>,
|
||||
},
|
||||
{
|
||||
view: <Revision repoUrl={app.spec.source.repoURL} revision={app.spec.source.targetRevision || 'HEAD'}/>,
|
||||
edit: (formApi: FormApi) => <FormField formApi={formApi} field='spec.source.targetRevision' component={Text} componentProps={{placeholder: 'HEAD'}} />,
|
||||
}, {
|
||||
title: 'PATH',
|
||||
view: app.spec.source.path,
|
||||
edit: (formApi: FormApi) => <FormField formApi={formApi} field='spec.source.path' component={Text}/>,
|
||||
},
|
||||
}]),
|
||||
{title: 'STATUS', view: (
|
||||
<span><ComparisonStatusIcon status={app.status.sync.status}/> {app.status.sync.status} {syncStatusMessage(app)}
|
||||
</span>
|
||||
|
|
@ -169,7 +197,7 @@ export const ApplicationSummary = (props: {
|
|||
const appURL = `${location.protocol}//${location.host}/applications/${props.app.metadata.name}`;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className='application-summary'>
|
||||
<EditablePanel
|
||||
save={props.updateApp}
|
||||
validate={(input) => ({
|
||||
|
|
@ -263,6 +291,6 @@ export const ApplicationSummary = (props: {
|
|||
)}
|
||||
</DataLoader>
|
||||
<EditablePanel save={(props.updateApp)} values={app} title='Info' items={infoItems} onModeSwitch={() => setAdjustedCount(0)}/>
|
||||
</React.Fragment>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ export const ApplicationSyncPanel = ({application, selectedResource, hide}: {
|
|||
{isVisible && (
|
||||
<Form
|
||||
defaultValues={{
|
||||
revision: application.spec.source.targetRevision,
|
||||
revision: application.spec.source.targetRevision || 'HEAD',
|
||||
resources: appResources.filter((item) => !item.hook).map((_, i) => i === syncResIndex || syncResIndex === -1),
|
||||
}}
|
||||
validateError={(values) => ({
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export class ApplicationsService {
|
|||
}
|
||||
|
||||
public revisionMetadata(name: string, revision: string): Promise<models.RevisionMetadata> {
|
||||
return requests.get(`/applications/${name}/revisions/${revision}/metadata`)
|
||||
return requests.get(`/applications/${name}/revisions/${revision || 'HEAD'}/metadata`)
|
||||
.then((res) => res.body as models.RevisionMetadata);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -270,6 +270,13 @@ func ValidatePermissions(ctx context.Context, spec *argoappv1.ApplicationSpec, p
|
|||
})
|
||||
return conditions, nil
|
||||
}
|
||||
if spec.Source.Chart != "" && spec.Source.TargetRevision == "" {
|
||||
conditions = append(conditions, argoappv1.ApplicationCondition{
|
||||
Type: argoappv1.ApplicationConditionInvalidSpecError,
|
||||
Message: "spec.source.targetRevision is required if the manifest source is a helm chart",
|
||||
})
|
||||
return conditions, nil
|
||||
}
|
||||
|
||||
if !proj.IsSourcePermitted(spec.Source) {
|
||||
conditions = append(conditions, argoappv1.ApplicationCondition{
|
||||
|
|
|
|||
|
|
@ -148,6 +148,23 @@ func TestValidatePermissionsEmptyDestination(t *testing.T) {
|
|||
assert.ElementsMatch(t, conditions, []argoappv1.ApplicationCondition{{Type: argoappv1.ApplicationConditionInvalidSpecError, Message: "Destination server and/or namespace missing from app spec"}})
|
||||
}
|
||||
|
||||
func TestValidateChartWithoutRevision(t *testing.T) {
|
||||
conditions, err := ValidatePermissions(context.Background(), &argoappv1.ApplicationSpec{
|
||||
Source: argoappv1.ApplicationSource{RepoURL: "https://kubernetes-charts-incubator.storage.googleapis.com/", Chart: "myChart", TargetRevision: ""},
|
||||
Destination: argoappv1.ApplicationDestination{
|
||||
Server: "https://kubernetes.default.svc", Namespace: "default",
|
||||
},
|
||||
}, &argoappv1.AppProject{
|
||||
Spec: argoappv1.AppProjectSpec{
|
||||
SourceRepos: []string{"*"},
|
||||
Destinations: []argoappv1.ApplicationDestination{{Server: "*", Namespace: "*"}},
|
||||
},
|
||||
}, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.ElementsMatch(t, conditions, []argoappv1.ApplicationCondition{{
|
||||
Type: argoappv1.ApplicationConditionInvalidSpecError, Message: "spec.source.targetRevision is required if the manifest source is a helm chart"}})
|
||||
}
|
||||
|
||||
func Test_enrichSpec(t *testing.T) {
|
||||
t.Run("Empty", func(t *testing.T) {
|
||||
spec := &argoappv1.ApplicationSpec{}
|
||||
|
|
|
|||
Loading…
Reference in a new issue