Skip to content
This repository has been archived by the owner on Jul 27, 2019. It is now read-only.

Commit

Permalink
Issue #474 - Load app details on the fly
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexander Matyushentsev authored and Alexander Matyushentsev committed Aug 3, 2018
1 parent 7c60ff0 commit 2956343
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 45 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { MockupList } from 'argo-ui';
import { MockupList, NotificationType } from 'argo-ui';
import * as path from 'path';
import * as PropTypes from 'prop-types';
import * as React from 'react';
import { BehaviorSubject } from 'rxjs';

import { ErrorNotification } from '../../../shared/components';
import { AppContext } from '../../../shared/context';
import * as models from '../../../shared/models';
import { ArgoApp, services } from '../../../shared/services';
import { services } from '../../../shared/services';

import { AppParams, AppsList, EnvironmentsList, NewAppParams, RepositoryList } from './steps';

Expand All @@ -16,10 +19,11 @@ interface StepInfo { title: string | React.ReactNode; canNext(): boolean; next()
interface State {
repos: models.Repository[];
clusters: models.Cluster[];
apps: ArgoApp[];
apps: models.AppInfo[];
envs: { [key: string]: models.KsonnetEnvironment; };
selectedRepo: string;
selectedApp: ArgoApp;
selectedApp: models.AppInfo;
selectedAppDetails: models.AppDetails;
selectedEnv: string;
appParams: NewAppParams;
appParamsValid: boolean;
Expand All @@ -33,6 +37,9 @@ export interface WizardProps { onStateChanged: (state: WizardStepState) => any;
export interface WizardStepState { nextTitle: string; next?: () => any; prev?: () => any; }

export class ApplicationCreationWizardContainer extends React.Component<WizardProps, State> {
public static contextTypes = {
apis: PropTypes.object,
};

private submitAppParamsForm = new BehaviorSubject<any>(null);

Expand All @@ -43,9 +50,10 @@ export class ApplicationCreationWizardContainer extends React.Component<WizardPr
clusters: [],
repos: [],
envs: {},
selectedApp: null,
selectedAppDetails: null,
selectedRepo: null,
selectedEnv: null,
selectedApp: null,
appParamsValid: false,
step: Step.SelectRepo,
loading: false,
Expand Down Expand Up @@ -99,25 +107,34 @@ export class ApplicationCreationWizardContainer extends React.Component<WizardPr
}, step: Step.SetParams })}>specify</a> drop-in YAML directory</div>
),
canNext: () => !!this.state.selectedApp,
next: () => {
if (this.state.selectedApp.ksonnet) {
this.updateState({ envs: this.state.selectedApp.ksonnet.environments, step: Step.SelectEnvironments});
} else {
this.updateState({ appParams: {
applicationName: this.state.selectedApp.helm.name,
repoURL: this.state.selectedRepo,
environment: '',
clusterURL: '',
namespace: '',
path: path.dirname(this.state.selectedApp.helm.path),
project: this.state.projects[0],
}, step: Step.SetParams });
next: async () => {
try {
this.updateState({ loading: true });
const selectedAppDetails = await services.reposService.appDetails(this.state.selectedRepo, this.state.selectedApp.path);

if (selectedAppDetails.ksonnet) {
this.updateState({ selectedAppDetails, envs: selectedAppDetails.ksonnet.environments || {}, step: Step.SelectEnvironments});
} else {
this.updateState({ selectedAppDetails, appParams: {
applicationName: selectedAppDetails.helm.name,
repoURL: this.state.selectedRepo,
environment: '',
clusterURL: '',
namespace: '',
path: path.dirname(selectedAppDetails.helm.path),
project: this.state.projects[0],
}, step: Step.SetParams });
}
} catch (e) {
this.appContext.apis.notifications.show({type: NotificationType.Error, content: <ErrorNotification title='Unable to load app details' e={e} />});
} finally {
this.updateState({ loading: false });
}
},
canPrev: () => true,
prev: () => this.updateState({ step: Step.SelectRepo }),
render: () => this.state.apps ? (
<AppsList apps={this.state.apps} selectedApp={this.state.selectedApp} onAppSelected={(app) => this.updateState({ selectedApp: app })}/>
<AppsList apps={this.state.apps} selectedApp={this.state.selectedApp} onAppSelected={(selectedApp) => this.updateState({ selectedApp })}/>
) : (
<MockupList height={50} marginTop={10}/>
),
Expand All @@ -130,12 +147,12 @@ export class ApplicationCreationWizardContainer extends React.Component<WizardPr
const selectedEnv = this.state.envs[this.state.selectedEnv];
this.updateState({
appParams: {
applicationName: `${this.state.selectedApp.ksonnet.name}-${this.state.selectedEnv}`,
applicationName: `${this.state.selectedAppDetails.ksonnet.name}-${this.state.selectedEnv}`,
repoURL: this.state.selectedRepo,
environment: this.state.selectedEnv,
clusterURL: selectedEnv.destination.server,
namespace: selectedEnv.destination.namespace,
path: path.dirname(this.state.selectedApp.ksonnet.path),
path: path.dirname(this.state.selectedAppDetails.ksonnet.path),
project: this.state.projects[0],
}, step: Step.SetParams,
});
Expand All @@ -153,15 +170,15 @@ export class ApplicationCreationWizardContainer extends React.Component<WizardPr
next: async () => this.submitAppParamsForm.next({}),
canPrev: () => true,
prev: async () => {
if (this.state.selectedApp && this.state.selectedApp.ksonnet) {
if (this.state.selectedAppDetails && this.state.selectedAppDetails.ksonnet) {
this.updateState({ step: Step.SelectEnvironments });
} else {
this.updateState({ step: Step.SelectApp });
}
},
render: () => (
<AppParams
needEnvironment={!!(this.state.selectedApp && this.state.selectedApp.ksonnet)}
needEnvironment={!!(this.state.selectedAppDetails && this.state.selectedAppDetails.ksonnet)}
projects={this.state.projects}
appParams={this.state.appParams}
submitForm={this.submitAppParamsForm}
Expand Down Expand Up @@ -209,4 +226,8 @@ export class ApplicationCreationWizardContainer extends React.Component<WizardPr
nextTitle: this.state.step === Step.SetParams ? 'Create' : 'Next',
});
}

private get appContext(): AppContext {
return this.context as AppContext;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ import { Observable, Subscription } from 'rxjs';
import { ConnectionStateIcon, FormField, Select } from '../../../shared/components';
import { AppContext } from '../../../shared/context';
import * as models from '../../../shared/models';
import { ArgoApp } from '../../../shared/services';

export const AppsList = (props: {
apps: ArgoApp[],
selectedApp: ArgoApp,
onAppSelected: (app: ArgoApp) => any,
apps: models.AppInfo[],
selectedApp: models.AppInfo,
onAppSelected: (app: models.AppInfo) => any,
}) => (
props.apps.length === 0 ? (
<div>
Expand All @@ -23,18 +22,14 @@ export const AppsList = (props: {
<div className='argo-table-list__head'>
<div className='row'>
<div className='columns small-2'>TYPE</div>
<div className='columns small-4'>APPLICATION NAME</div>
<div className='columns small-4'>PATH</div>
<div className='columns small-2'>ENVIRONMENTS COUNT</div>
<div className='columns small-10'>PATH</div>
</div>
</div>
{props.apps.map((item, i) => (
<div className={classNames('argo-table-list__row', { selected: item === props.selectedApp })} key={i} onClick={() => props.onAppSelected(item)}>
<div className='row'>
<div className='columns small-2'>{item.ksonnet && 'Ksonnet' || 'Helm'}</div>
<div className='columns small-4'>{(item.ksonnet || item.helm).name}</div>
<div className='columns small-4'>{(item.ksonnet || item.helm).path}</div>
<div className='columns small-2'>{item.ksonnet ? Object.keys(item.ksonnet.environments).length : 0}</div>
<div className='columns small-2'>{item.type}</div>
<div className='columns small-10'>{item.path}</div>
</div>
</div>
))}
Expand Down Expand Up @@ -84,6 +79,9 @@ export const EnvironmentsList = (props: {
onEnvsSelectionChanged: (env: string) => any;
}) => {
const environments = Object.keys(props.envs).map((name) => Object.assign(props.envs[name], {name}));
if (environments.length === 0) {
return <p>Application has no environments</p>;
}
return (
<div className='argo-table-list argo-table-list--clickable'>
<div className='argo-table-list__head'>
Expand Down
7 changes: 7 additions & 0 deletions src/app/shared/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,13 @@ export interface KsonnetAppSpec {
environments: { [key: string]: KsonnetEnvironment; };
}

export interface AppDetails { type: string; path: string; ksonnet?: KsonnetAppSpec; helm?: HelmAppSpec; }

export interface AppInfo {
type: string;
path: string;
}

export interface HelmAppSpec {
name: string;
path: string;
Expand Down
2 changes: 0 additions & 2 deletions src/app/shared/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,3 @@ export const services: Services = {
projects: new ProjectsService(),
viewPreferences: new ViewPreferencesService(),
};

export { ArgoApp } from './repo-service';
16 changes: 7 additions & 9 deletions src/app/shared/services/repo-service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import * as models from '../models';
import requests from './requests';

export interface ArgoApp { ksonnet?: models.KsonnetAppSpec; helm?: models.HelmAppSpec; }

export class RepositoriesService {
public list(): Promise<models.Repository[]> {
return requests.get('/repositories').then((res) => res.body as models.RepositoryList).then((list) => list.items || []);
Expand All @@ -16,13 +14,13 @@ export class RepositoriesService {
return requests.delete(`/repositories/${encodeURIComponent(url)}`).send().then((res) => res.body as models.Repository);
}

public apps(repo: string): Promise<ArgoApp[]> {
public apps(repo: string): Promise<models.AppInfo[]> {
return requests.get(`/repositories/${encodeURIComponent(repo)}/apps`)
.then((res) => {
const body = res.body as { ksonnetApps: models.KsonnetAppSpec[], helmApps: models.HelmAppSpec[] };
const ksonnet = (body.ksonnetApps || []).map((item) => ({ ksonnet: item, helm: null }));
const helm = (body.helmApps || []).map((item) => ({ ksonnet: null, helm: item }));
return ksonnet.concat(helm);
});
.then((res) => res.body.items as models.AppInfo[]);
}

public appDetails(repo: string, path: string): Promise<models.AppDetails> {
return requests.get(`/repositories/${encodeURIComponent(repo)}/apps/${encodeURIComponent(path)}`)
.then((res) => res.body as models.AppDetails);
}
}

0 comments on commit 2956343

Please sign in to comment.