Skip to content

Commit

Permalink
feat: Add Sources tab to show all sources of a multi-source app (argo…
Browse files Browse the repository at this point in the history
…proj#17274)

Signed-off-by: Keith Chong <kykchong@redhat.com>
  • Loading branch information
keithchong committed Feb 22, 2024
1 parent 6aa79f2 commit f2db50e
Show file tree
Hide file tree
Showing 6 changed files with 539 additions and 284 deletions.

Large diffs are not rendered by default.

Expand Up @@ -169,7 +169,7 @@ export const ApplicationSummary = (props: ApplicationSummaryProps) => {
title: 'CREATED AT',
view: formatCreationTimestamp(app.metadata.creationTimestamp)
},
{
!hasMultipleSources && {
title: 'REPO URL',
view: <Repo url={source.repoURL} />,
edit: (formApi: FormApi) =>
Expand All @@ -179,88 +179,89 @@ export const ApplicationSummary = (props: ApplicationSummaryProps) => {
<FormField formApi={formApi} field='spec.source.repoURL' component={Text} />
)
},
...(isHelm
? [
{
title: 'CHART',
view: (
<span>
{source.chart}:{source.targetRevision}
</span>
),
edit: (formApi: FormApi) =>
hasMultipleSources ? (
helpTip('CHART is not editable for applications with multiple sources. You can edit them in the "Manifest" tab.')
) : (
<DataLoader
input={{repoURL: getAppSpecDefaultSource(formApi.getFormState().values.spec).repoURL}}
load={src => services.repos.charts(src.repoURL).catch(() => new Array<models.HelmChart>())}>
{(charts: models.HelmChart[]) => (
<div className='row'>
<div className='columns small-8'>
<FormField
formApi={formApi}
field='spec.source.chart'
component={AutocompleteField}
componentProps={{
items: charts.map(chart => chart.name),
filterSuggestions: true
}}
/>
...(!hasMultipleSources
? isHelm
? [
{
title: 'CHART',
view: (
<span>
{source.chart}:{source.targetRevision}
</span>
),
edit: (formApi: FormApi) =>
hasMultipleSources ? (
helpTip('CHART is not editable for applications with multiple sources. You can edit them in the "Manifest" tab.')
) : (
<DataLoader
input={{repoURL: getAppSpecDefaultSource(formApi.getFormState().values.spec).repoURL}}
load={src => services.repos.charts(src.repoURL).catch(() => new Array<models.HelmChart>())}>
{(charts: models.HelmChart[]) => (
<div className='row'>
<div className='columns small-8'>
<FormField
formApi={formApi}
field='spec.source.chart'
component={AutocompleteField}
componentProps={{
items: charts.map(chart => chart.name),
filterSuggestions: true
}}
/>
</div>
<DataLoader
input={{charts, chart: getAppSpecDefaultSource(formApi.getFormState().values.spec).chart}}
load={async data => {
const chartInfo = data.charts.find(chart => chart.name === data.chart);
return (chartInfo && chartInfo.versions) || new Array<string>();
}}>
{(versions: string[]) => (
<div className='columns small-4'>
<FormField
formApi={formApi}
field='spec.source.targetRevision'
component={AutocompleteField}
componentProps={{
items: versions
}}
/>
<RevisionHelpIcon type='helm' top='0' />
</div>
)}
</DataLoader>
</div>
<DataLoader
input={{charts, chart: getAppSpecDefaultSource(formApi.getFormState().values.spec).chart}}
load={async data => {
const chartInfo = data.charts.find(chart => chart.name === data.chart);
return (chartInfo && chartInfo.versions) || new Array<string>();
}}>
{(versions: string[]) => (
<div className='columns small-4'>
<FormField
formApi={formApi}
field='spec.source.targetRevision'
component={AutocompleteField}
componentProps={{
items: versions
}}
/>
<RevisionHelpIcon type='helm' top='0' />
</div>
)}
</DataLoader>
</div>
)}
</DataLoader>
)
}
]
: [
{
title: 'TARGET REVISION',
view: <Revision repoUrl={source.repoURL} revision={source.targetRevision || 'HEAD'} />,
edit: (formApi: FormApi) =>
hasMultipleSources ? (
helpTip('TARGET REVISION is not editable for applications with multiple sources. You can edit them in the "Manifest" tab.')
) : (
<RevisionFormField helpIconTop={'0'} hideLabel={true} formApi={formApi} repoURL={source.repoURL} />
)
},
{
title: 'PATH',
view: (
<Revision repoUrl={source.repoURL} revision={source.targetRevision || 'HEAD'} path={source.path} isForPath={true}>
{processPath(source.path)}
</Revision>
),
edit: (formApi: FormApi) =>
hasMultipleSources ? (
helpTip('PATH is not editable for applications with multiple sources. You can edit them in the "Manifest" tab.')
) : (
<FormField formApi={formApi} field='spec.source.path' component={Text} />
)
}
]),

)}
</DataLoader>
)
}
]
: [
{
title: 'TARGET REVISION',
view: <Revision repoUrl={source.repoURL} revision={source.targetRevision || 'HEAD'} />,
edit: (formApi: FormApi) =>
hasMultipleSources ? (
helpTip('TARGET REVISION is not editable for applications with multiple sources. You can edit them in the "Manifest" tab.')
) : (
<RevisionFormField helpIconTop={'0'} hideLabel={true} formApi={formApi} repoURL={source.repoURL} />
)
},
{
title: 'PATH',
view: (
<Revision repoUrl={source.repoURL} revision={source.targetRevision || 'HEAD'} path={source.path} isForPath={true}>
{processPath(source.path)}
</Revision>
),
edit: (formApi: FormApi) =>
hasMultipleSources ? (
helpTip('PATH is not editable for applications with multiple sources. You can edit them in the "Manifest" tab.')
) : (
<FormField formApi={formApi} field='spec.source.path' component={Text} />
)
}
]
: []),
{
title: 'REVISION HISTORY LIMIT',
view: app.spec.revisionHistoryLimit,
Expand Down
Expand Up @@ -40,6 +40,7 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
const tab = new URLSearchParams(appContext.history.location.search).get('tab');
const selectedNodeInfo = NodeInfo(new URLSearchParams(appContext.history.location.search).get('node'));
const selectedNodeKey = selectedNodeInfo.key;
const [pageNumber, setPageNumber] = React.useState(0);

const getResourceTabs = (
node: ResourceNode,
Expand Down Expand Up @@ -161,23 +162,18 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
content: <ApplicationSummary app={application} updateApp={(app, query: {validate?: boolean}) => updateApp(app, query)} />
},
{
title: 'PARAMETERS',
key: 'parameters',
title: 'INPUTS/SOURCES',
key: 'sources',
content: (
<DataLoader
key='appDetails'
input={application}
load={app =>
services.repos.appDetails(AppUtils.getAppDefaultSource(app), app.metadata.name, app.spec.project).catch(() => ({
type: 'Directory' as AppSourceType,
path: AppUtils.getAppDefaultSource(app).path
}))
}>
{(details: RepoAppDetails) => (
<DataLoader key='appDetails' input={application} load={app => getSources(app)}>
{(details: RepoAppDetails[]) => (
<ApplicationParameters
save={(app: models.Application, query: {validate?: boolean}) => updateApp(app, query)}
application={application}
details={details}
details={details[0]}
detailsList={details}
pageNumber={pageNumber}
setPageNumber={setPageNumber}
/>
)}
</DataLoader>
Expand Down Expand Up @@ -368,3 +364,32 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
</div>
);
};

// Maintain compatibility with single source field. Remove else block when source field is removed
async function getSources(app: models.Application) {
const listOfDetails = new Array<RepoAppDetails & {type: AppSourceType; path: string}>();
const sources: models.ApplicationSource[] = AppUtils.getAppSources(app);
if (sources) {
const length = sources.length;
for (let i = 0; i < length; i++) {
const aSource = sources[i];
const repoDetail = await services.repos.appDetails(aSource, app.metadata.name, app.spec.project).catch(e => ({
type: 'Directory' as AppSourceType,
path: aSource.path
}));
if (repoDetail) {
listOfDetails.push(repoDetail);
}
}
return listOfDetails;
} else {
const repoDetail = await services.repos.appDetails(AppUtils.getAppDefaultSource(app), app.metadata.name, app.spec.project).catch(() => ({
type: 'Directory' as AppSourceType,
path: AppUtils.getAppDefaultSource(app).path
}));
if (repoDetail) {
listOfDetails.push(repoDetail);
}
return listOfDetails;
}
}
7 changes: 7 additions & 0 deletions ui/src/app/applications/components/utils.tsx
Expand Up @@ -1029,6 +1029,13 @@ export function getAppDefaultSource(app?: appModels.Application) {
return app.spec.sources && app.spec.sources.length > 0 ? app.spec.sources[0] : app.spec.source;
}

export function getAppSources(app?: appModels.Application): appModels.ApplicationSource[] {
if (!app) {
return null;
}
return app.spec.sources;
}

export function getAppSpecDefaultSource(spec: appModels.ApplicationSpec) {
return spec.sources && spec.sources.length > 0 ? spec.sources[0] : spec.source;
}
Expand Down
Expand Up @@ -13,6 +13,12 @@
right: 3em;
}

&__collapsible-button {
position: absolute;
top: 30px;
right: 30px;
}

.form-field__select {
line-height: 15px;
padding: 0;
Expand Down

0 comments on commit f2db50e

Please sign in to comment.