Skip to content

Commit

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

* feat: Add Sources tab to show all sources of a multi-source app (#17274)

Signed-off-by: Keith Chong <kykchong@redhat.com>

* Update ui/src/app/applications/components/resource-details/resource-details.tsx

Co-authored-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
Signed-off-by: Keith Chong <kykchong@redhat.com>

* Remove getAppSources

Signed-off-by: Keith Chong <kykchong@redhat.com>

* Add address Ishita's comments. Add missing Ref field

Signed-off-by: Keith Chong <kykchong@redhat.com>

* Use single quotes

Signed-off-by: Keith Chong <kykchong@redhat.com>

---------

Signed-off-by: Keith Chong <kykchong@redhat.com>
Co-authored-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
  • Loading branch information
keithchong and agaudreault committed Apr 16, 2024
1 parent a1472ae commit f819870
Show file tree
Hide file tree
Showing 6 changed files with 562 additions and 275 deletions.

Large diffs are not rendered by default.

Expand Up @@ -170,7 +170,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 @@ -180,88 +180,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: '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[] = app.spec.sources;
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;
}
}
20 changes: 20 additions & 0 deletions ui/src/app/shared/components/editable-panel/editable-panel.scss
Expand Up @@ -13,6 +13,26 @@
right: 3em;
}

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

&__sticky-title {
z-index: 10;
opacity: 75%;
position: sticky;
padding-left: 15px;
padding-right: 15px;
margin-bottom: 5px;
text-align: center;
top: 0px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}

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

0 comments on commit f819870

Please sign in to comment.