Skip to content

Commit

Permalink
fix(core): request project pipeline configs just in time (#6980)
Browse files Browse the repository at this point in the history
  • Loading branch information
maggieneterval authored and anotherchrisberry committed May 15, 2019
1 parent cfd7690 commit 0fc8946
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ import * as React from 'react';

import { AccountService, IAccount } from 'core/account';
import { ApplicationReader, IApplicationSummary } from 'core/application';
import { IPipeline, IProject } from 'core/domain';
import { IProject } from 'core/domain';
import { WizardModal, WizardPage } from 'core/modal';
import { PipelineConfigService } from 'core/pipeline';
import { IModalComponentProps, ReactModal } from 'core/presentation';
import { TaskMonitor } from 'core/task';
import { noop } from 'core/utils';
Expand All @@ -28,9 +27,6 @@ export interface IConfigureProjectModalState {
allAccounts: IAccount[];
allProjects: IProject[];
allApplications: IApplicationSummary[];
appPipelines: {
[appName: string]: IPipeline[];
};
configuredApps: string[];
loading: boolean;
taskMonitor?: TaskMonitor;
Expand All @@ -47,7 +43,6 @@ export class ConfigureProjectModal extends React.Component<IConfigureProjectModa
allAccounts: [],
allProjects: [],
allApplications: [],
appPipelines: {},
configuredApps: [],
};

Expand All @@ -74,15 +69,12 @@ export class ConfigureProjectModal extends React.Component<IConfigureProjectModa

private handleApplicationsChanged = (configuredApps: string[]) => {
this.setState({ configuredApps });
this.fetchPipelinesForApps(configuredApps);
};

public componentDidMount() {
const { projectConfiguration } = this.props;
const configuredApps = (projectConfiguration && projectConfiguration.config.applications) || [];
Promise.all([this.fetchPipelinesForApps(configuredApps), this.initialFetch()]).then(() =>
this.setState({ loading: false, configuredApps }),
);
Promise.all([this.initialFetch()]).then(() => this.setState({ loading: false, configuredApps }));
}

private submit = (project: IProject) => {
Expand Down Expand Up @@ -110,21 +102,6 @@ export class ConfigureProjectModal extends React.Component<IConfigureProjectModa
);
}

private fetchPipelinesForApps = (applications: string[]) => {
// Only fetch for apps we don't already have results for
const appsToFetch = applications.filter(appName => !this.state.appPipelines[appName]);

const fetches = appsToFetch.map(appName => {
return PipelineConfigService.getPipelinesForApplication(appName).then(pipelines =>
this.setState({
appPipelines: { ...this.state.appPipelines, [appName]: pipelines },
}),
);
});

return Promise.all(fetches);
};

private onDelete = () => {
const { projectConfiguration } = this.props;
const { name } = projectConfiguration;
Expand All @@ -142,7 +119,7 @@ export class ConfigureProjectModal extends React.Component<IConfigureProjectModa

public render() {
const { dismissModal, projectConfiguration } = this.props;
const { allAccounts, allApplications, allProjects, appPipelines, loading, taskMonitor } = this.state;
const { allAccounts, allApplications, allProjects, loading, taskMonitor } = this.state;
const appNames = allApplications.map(app => app.name);

return (
Expand Down Expand Up @@ -190,7 +167,7 @@ export class ConfigureProjectModal extends React.Component<IConfigureProjectModa
label="Pipelines"
wizard={wizard}
order={nextIdx()}
render={({ innerRef }) => <Pipelines ref={innerRef} appsPipelines={appPipelines} />}
render={({ innerRef }) => <Pipelines ref={innerRef} formik={formik} />}
/>
</>
)}
Expand Down
60 changes: 51 additions & 9 deletions app/scripts/modules/core/src/projects/configure/Pipelines.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
import * as React from 'react';
import { FieldArray, FormikErrors, getIn } from 'formik';
import { FieldArray, FormikErrors, FormikProps, getIn } from 'formik';
import { chain, each, get, isEqual } from 'lodash';

import { PipelineConfigService } from 'core/pipeline';
import { FormikFormField, ReactSelectInput, StringsAsOptions } from 'core/presentation';
import { Spinner } from 'core/widgets';
import { IPipeline, IProject, IProjectPipeline } from 'core/domain';
import { IWizardPageComponent } from 'core/modal';

export interface IPipelinesProps {
formik: FormikProps<IProject>;
}

export interface IPipelinesState {
appsPipelines: {
[appName: string]: IPipeline[];
};
}

export class Pipelines extends React.Component<IPipelinesProps> implements IWizardPageComponent<IProject> {
export class Pipelines extends React.Component<IPipelinesProps, IPipelinesState>
implements IWizardPageComponent<IProject> {
private static readonly pipelineConfigsPath = 'config.pipelineConfigs';

public state: IPipelinesState = {
appsPipelines: {},
};

public validate = (value: IProject): FormikErrors<IProject> => {
const projectApplications = (value.config && value.config.applications) || [];
const { appsPipelines } = this.props;
const { appsPipelines } = this.state;

if (value.config && value.config.pipelineConfigs && value.config.pipelineConfigs.length) {
const pipelineConfigErrors = value.config.pipelineConfigs.map(config => {
Expand Down Expand Up @@ -46,8 +59,39 @@ export class Pipelines extends React.Component<IPipelinesProps> implements IWiza
return {};
};

private getProjectPipelines = (props: IPipelinesProps): IProjectPipeline[] => {
return get(props.formik.values, Pipelines.pipelineConfigsPath, []);
};

private fetchPipelinesForApps = (projectPipelines: IProjectPipeline[]) => {
const appsToFetch = chain(projectPipelines)
.map('application')
.uniq()
// Only fetch for apps we don't already have results for
.filter(appName => appName && !this.state.appsPipelines[appName])
.value();

each(appsToFetch, appName => {
PipelineConfigService.getPipelinesForApplication(appName).then(pipelines =>
this.setState({
appsPipelines: { ...this.state.appsPipelines, [appName]: pipelines },
}),
);
});
};

public componentDidMount() {
this.fetchPipelinesForApps(this.getProjectPipelines(this.props));
}

public componentDidUpdate(prevProps: IPipelinesProps) {
if (!isEqual(this.getProjectPipelines(prevProps), this.getProjectPipelines(this.props))) {
this.fetchPipelinesForApps(this.getProjectPipelines(this.props));
}
}

public render() {
const { appsPipelines } = this.props;
const { appsPipelines } = this.state;

const tableHeader = (
<tr>
Expand All @@ -57,14 +101,12 @@ export class Pipelines extends React.Component<IPipelinesProps> implements IWiza
</tr>
);

const pipelineConfigsPath = 'config.pipelineConfigs';

return (
<FieldArray
name={pipelineConfigsPath}
name={Pipelines.pipelineConfigsPath}
render={pipelinesArrayHelper => {
const project: IProject = pipelinesArrayHelper.form.values;
const configs: IProjectPipeline[] = getIn(project, pipelineConfigsPath);
const configs: IProjectPipeline[] = getIn(project, Pipelines.pipelineConfigsPath);
const apps: string[] = getIn(project, 'config.applications');

return (
Expand All @@ -74,7 +116,7 @@ export class Pipelines extends React.Component<IPipelinesProps> implements IWiza
<thead>{tableHeader}</thead>
<tbody>
{configs.map((config, idx) => {
const pipelinePath = `${pipelineConfigsPath}[${idx}]`;
const pipelinePath = `${Pipelines.pipelineConfigsPath}[${idx}]`;
const application = config && config.application;
const appPipelines = application && appsPipelines[application];
const pipelineOptions = appPipelines && appPipelines.map(p => ({ label: p.name, value: p.id }));
Expand Down

0 comments on commit 0fc8946

Please sign in to comment.