diff options
Diffstat (limited to 'catalog-ui/src/app/ng2/store')
7 files changed, 469 insertions, 0 deletions
diff --git a/catalog-ui/src/app/ng2/store/actions/artifacts.action.ts b/catalog-ui/src/app/ng2/store/actions/artifacts.action.ts new file mode 100644 index 0000000000..a00cc3a9ec --- /dev/null +++ b/catalog-ui/src/app/ng2/store/actions/artifacts.action.ts @@ -0,0 +1,25 @@ +/** + * Created by ob0695 + */ +import {ArtifactModel} from "../../../models/artifacts"; + +export class GetArtifactsByTypeAction { + static readonly type = '[ARTIFACTS] GetArtifactsByType'; + + constructor(public payload: {componentType:string, componentId:string, artifactType: string}) { + } +} + +export class CreateOrUpdateArtifactAction { + static readonly type = '[ARTIFACTS] CreateOrUpdateArtifactAction'; + + constructor(public payload: {componentType:string, componentId:string, artifact:ArtifactModel}) { + } +} + +export class DeleteArtifactAction { + static readonly type = '[ARTIFACTS] DeleteArtifactAction'; + + constructor(public payload: {componentType:string, componentId:string, artifact: ArtifactModel}) { + } +} diff --git a/catalog-ui/src/app/ng2/store/actions/instance-artifacts.actions.ts b/catalog-ui/src/app/ng2/store/actions/instance-artifacts.actions.ts new file mode 100644 index 0000000000..0f1df78352 --- /dev/null +++ b/catalog-ui/src/app/ng2/store/actions/instance-artifacts.actions.ts @@ -0,0 +1,32 @@ +/** + * Created by ob0695 + */ +import {ArtifactModel} from "../../../models/artifacts"; + +export class GetInstanceArtifactsByTypeAction { + static readonly type = '[INSTANCE_ARTIFACTS] GetInstanceArtifactsByTypeAction'; + + constructor(public payload: { componentType: string, componentId: string, artifactType: string, instanceId: string }) { + } +} + +export class CreateInstanceArtifactAction { + static readonly type = '[INSTANCE_ARTIFACTS] CreateInstanceArtifactAction'; + + constructor(public payload: { componentType: string, componentId: string, instanceId: string, artifact: ArtifactModel }) { + } +} + +export class UpdateInstanceArtifactAction { + static readonly type = '[INSTANCE_ARTIFACTS] UpdateInstanceArtifactAction'; + + constructor(public payload: { componentType: string, componentId: string, instanceId: string, artifact: ArtifactModel }) { + } +} + +export class DeleteInstanceArtifactAction { + static readonly type = '[INSTANCE_ARTIFACTS] DeleteInstanceArtifactAction'; + + constructor(public payload: { componentType: string, componentId: string, instanceId: string, artifact: ArtifactModel }) { + } +} diff --git a/catalog-ui/src/app/ng2/store/actions/workspace.action.ts b/catalog-ui/src/app/ng2/store/actions/workspace.action.ts new file mode 100644 index 0000000000..c7f18e0ac6 --- /dev/null +++ b/catalog-ui/src/app/ng2/store/actions/workspace.action.ts @@ -0,0 +1,17 @@ +/** + * Created by ob0695 on 7/17/2018. + */ + +export class UpdateIsViewOnly { + static readonly type = '[WORKSPACE] UpdateIsViewOnly'; + + constructor(public isViewOnly:boolean) { + } +} + +export class UpdateIsDesigner { + static readonly type = '[WORKSPACE] UpdateIsDesigner'; + + constructor(public isDesigner:boolean) { + } +} diff --git a/catalog-ui/src/app/ng2/store/states/artifacts.state.spec.ts b/catalog-ui/src/app/ng2/store/states/artifacts.state.spec.ts new file mode 100644 index 0000000000..c59a4455b6 --- /dev/null +++ b/catalog-ui/src/app/ng2/store/states/artifacts.state.spec.ts @@ -0,0 +1,62 @@ +import { Store } from '@ngxs/store'; +import { Observable } from 'rxjs/Rx'; +import { Mock } from 'ts-mockery'; +import { ArtifactModel } from '../../../models/artifacts'; +import { ArtifactGroupType } from '../../../utils/constants'; +import { ComponentInstanceServiceNg2 } from '../../services/component-instance-services/component-instance.service'; +import { GetInstanceArtifactsByTypeAction, UpdateInstanceArtifactAction } from '../actions/instance-artifacts.actions'; +import { InstanceArtifactsState } from './instance-artifacts.state'; + +describe('Test Artifact State', () => { + + const heat1 = Mock.of<ArtifactModel>({ + uniqueId: '1', artifactName: 'heat1', timeout: 0, artifactDisplayName: 'heat1', artifactGroupType: ArtifactGroupType.DEPLOYMENT + }); + + const heat1env = Mock.of<ArtifactModel>({ + uniqueId: '2', artifactName: 'heat1env', timeout: 0, generatedFromId: '1', artifactDisplayName: 'heat1env', artifactGroupType: ArtifactGroupType.DEPLOYMENT + }); + + const storeMock = Mock.of<Store>( { dispatch : jest.fn() }); + + const artifacts = [ + heat1, + heat1env + ]; + + /** + * NGXS Store state before we run the update + */ + const ngxsState = { + deploymentArtifacts : artifacts + }; + + /** + * The ENV artifact that we wish to update + */ + const updatedArtifact = Mock.of<ArtifactModel>({ + uniqueId: '2', artifactName: 'heat1env', timeout: 33, generatedFromId: '1', artifactDisplayName: 'heat1env-UPDATE', artifactGroupType: ArtifactGroupType.DEPLOYMENT + }); + + const componentInstanceServiceMock: ComponentInstanceServiceNg2 = Mock.of<ComponentInstanceServiceNg2>({ + updateInstanceArtifact: jest.fn().mockImplementation(() => Observable.of(updatedArtifact)), + getComponentInstanceArtifactsByGroupType: jest.fn().mockImplementation(() => Observable.of([heat1, updatedArtifact])) + }); + + const actionMock: UpdateInstanceArtifactAction = Mock.of<UpdateInstanceArtifactAction>({ + payload: { + componentType: '', + componentId: '', + instanceId: '', + artifact: updatedArtifact + } + }); + + it('Test that HEAT timeout is updated', () => { + const state: InstanceArtifactsState = new InstanceArtifactsState(storeMock, componentInstanceServiceMock); + const context = { getState: jest.fn().mockImplementation(() => ngxsState), patchState: jest.fn(), setState: jest.fn(), dispatch: jest.fn() }; + state.updateArtifact(context, actionMock ).subscribe( (v) => console.log('OK')); + expect(storeMock.dispatch).toBeCalled(); + }); + +}); diff --git a/catalog-ui/src/app/ng2/store/states/artifacts.state.ts b/catalog-ui/src/app/ng2/store/states/artifacts.state.ts new file mode 100644 index 0000000000..64efbe96a9 --- /dev/null +++ b/catalog-ui/src/app/ng2/store/states/artifacts.state.ts @@ -0,0 +1,140 @@ +/** + * Created by ob0695 on 7/17/2018. + */ +import { Action, Selector, State, StateContext } from '@ngxs/store'; +import * as _ from 'lodash'; +import { tap } from 'rxjs/operators'; +import { ArtifactModel } from '../../../models/artifacts'; +import { ArtifactGroupType } from '../../../utils/constants'; +import { TopologyTemplateService } from '../../services/component-services/topology-template.service'; +import { ComponentGenericResponse } from '../../services/responses/component-generic-response'; +import { ServiceGenericResponse } from '../../services/responses/service-generic-response'; +import { CreateOrUpdateArtifactAction, DeleteArtifactAction, GetArtifactsByTypeAction } from '../actions/artifacts.action'; + +export interface ArtifactsStateModel { + artifacts: ArtifactModel[]; + deploymentArtifacts: ArtifactModel[]; + toscaArtifacts: ArtifactModel[]; + serviceApiArtifacts: ArtifactModel[]; +} + +@State<ArtifactsStateModel>({ + name: 'artifacts', + defaults: { + artifacts: [], + deploymentArtifacts: [], + toscaArtifacts: [], + serviceApiArtifacts: [] + } +}) + +export class ArtifactsState { + + constructor(protected topologyTemplateService: TopologyTemplateService) { + } + + @Selector() + static getEnvArtifact(state: ArtifactsStateModel, heatEnvArtifact: ArtifactModel) { + return (heatEnvArtifact: ArtifactModel) => { + _.find(state.deploymentArtifacts, (artifact)=> { + return artifact.generatedFromId === heatEnvArtifact.uniqueId + }) + }; + } + + @Selector() + static getArtifactsByType(state: ArtifactsStateModel, type: string) { + return (type: string) => { + switch (type) { + case ArtifactGroupType.TOSCA: + return state.toscaArtifacts; + case ArtifactGroupType.INFORMATION: + return state.artifacts; + case ArtifactGroupType.DEPLOYMENT: + return state.deploymentArtifacts; + case ArtifactGroupType.SERVICE_API: + return state.serviceApiArtifacts; + } + }; + } + + private updateArtifactState = (artifactsState: ArtifactModel[], artifactToUpdate: ArtifactModel, updatedArtifact: ArtifactModel) => { + if (!artifactToUpdate.uniqueId) { // Create Artifact + return [...artifactsState, updatedArtifact] + } else { // Update Artifact + let artifactToUpdateIndex = _.findIndex(artifactsState, (artifact) => { + return artifact.uniqueId === artifactToUpdate.uniqueId + }) + let artifacts = Array.from(artifactsState); + artifacts[artifactToUpdateIndex] = updatedArtifact; + return [...artifacts]; + } + } + + @Action(GetArtifactsByTypeAction) + getArtifactsByType({getState, patchState}: StateContext<ArtifactsStateModel>, action: GetArtifactsByTypeAction) { + const state = getState(); + return this.topologyTemplateService.getArtifactsByType(action.payload.componentType, action.payload.componentId, action.payload.artifactType) + .pipe(tap((resp: ComponentGenericResponse) => { + switch (action.payload.artifactType) { + case ArtifactGroupType.INFORMATION: + patchState({ + artifacts: <ArtifactModel[]>_.values(resp.artifacts) + }); + + case ArtifactGroupType.DEPLOYMENT: + patchState({ + deploymentArtifacts: <ArtifactModel[]>_.values(resp.deploymentArtifacts) + }); + + case ArtifactGroupType.TOSCA: + patchState({ + toscaArtifacts: <ArtifactModel[]>_.values(resp.toscaArtifacts) + }); + + case ArtifactGroupType.SERVICE_API: + patchState({ + serviceApiArtifacts: <ArtifactModel[]>_.values((<ServiceGenericResponse>resp).serviceApiArtifacts) + }); + } + })); + } + + @Action(CreateOrUpdateArtifactAction) + createOrUpdateArtifact({getState, patchState}: StateContext<ArtifactsStateModel>, action: CreateOrUpdateArtifactAction) { + const state = getState(); + return this.topologyTemplateService.addOrUpdateArtifact(action.payload.componentType, action.payload.componentId, action.payload.artifact) + .pipe(tap((resp: ArtifactModel) => { + + switch (resp.artifactGroupType) { + case ArtifactGroupType.DEPLOYMENT: + patchState({ + deploymentArtifacts: this.updateArtifactState(state.deploymentArtifacts, action.payload.artifact, resp) + }); + + case ArtifactGroupType.INFORMATION: + patchState({ + artifacts: this.updateArtifactState(state.artifacts, action.payload.artifact, resp) + }); + } + })); + } + + @Action(DeleteArtifactAction) + deleteArtifact({getState, patchState}: StateContext<ArtifactsStateModel>, action: DeleteArtifactAction) { + const state = getState(); + return this.topologyTemplateService.deleteArtifact(action.payload.componentId, action.payload.componentType, action.payload.artifact.uniqueId, action.payload.artifact.artifactLabel) + .pipe(tap((resp: ArtifactModel) => { + switch (resp.artifactGroupType) { + case ArtifactGroupType.DEPLOYMENT: + patchState({ + deploymentArtifacts: state.deploymentArtifacts.filter(({uniqueId}) => uniqueId !== action.payload.artifact.uniqueId) + }); + case ArtifactGroupType.INFORMATION: + patchState({ + artifacts: state.artifacts.filter(({uniqueId}) => uniqueId !== action.payload.artifact.uniqueId) + }); + } + })); + } +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/store/states/instance-artifacts.state.ts b/catalog-ui/src/app/ng2/store/states/instance-artifacts.state.ts new file mode 100644 index 0000000000..12ba1ae7ba --- /dev/null +++ b/catalog-ui/src/app/ng2/store/states/instance-artifacts.state.ts @@ -0,0 +1,145 @@ +/** + * Created by ob0695 on 7/17/2018. + */ +import { Action, Selector, State, StateContext, Store } from '@ngxs/store'; +import * as _ from 'lodash'; +import { tap } from 'rxjs/operators'; +import { ArtifactModel } from '../../../models/artifacts'; +import { ArtifactGroupType } from '../../../utils/constants'; +import { ComponentInstanceServiceNg2 } from '../../services/component-instance-services/component-instance.service'; +import { ComponentGenericResponse } from '../../services/responses/component-generic-response'; +import { + CreateInstanceArtifactAction, + DeleteInstanceArtifactAction, + GetInstanceArtifactsByTypeAction, + UpdateInstanceArtifactAction +} from '../actions/instance-artifacts.actions'; +import { ArtifactsStateModel } from './artifacts.state'; + +export interface InstanceArtifactsStateModel { + artifacts: ArtifactModel[]; + deploymentArtifacts: ArtifactModel[]; +} + +@State<InstanceArtifactsStateModel>({ + name: 'instance_artifacts', + defaults: { + artifacts: [], + deploymentArtifacts: [] + } +}) +export class InstanceArtifactsState { + + constructor(private store: Store, protected componentInstanceService: ComponentInstanceServiceNg2) { + } + + @Selector() + static getArtifactsByType(state: InstanceArtifactsStateModel) { + return (type: string) => { + switch (type) { + case ArtifactGroupType.INFORMATION: + return state.artifacts; + case ArtifactGroupType.DEPLOYMENT: + return state.deploymentArtifacts; + } + }; + } + + @Action(GetInstanceArtifactsByTypeAction) + getInstanceArtifactsByType({getState, patchState}: StateContext<InstanceArtifactsStateModel>, action: GetInstanceArtifactsByTypeAction) { + const state = getState(); + return this.componentInstanceService.getComponentInstanceArtifactsByGroupType(action.payload.componentType, action.payload.componentId, action.payload.instanceId, action.payload.artifactType) + .pipe(tap((resp: ComponentGenericResponse) => { + switch (action.payload.artifactType) { + case ArtifactGroupType.INFORMATION: + patchState({ + artifacts: _.values(resp) as ArtifactModel[] + }); + break; + case ArtifactGroupType.DEPLOYMENT: + patchState({ + deploymentArtifacts: _.values(resp) as ArtifactModel[] + }); + break; + } + })); + } + + @Action(CreateInstanceArtifactAction) + createArtifact({getState, patchState}: StateContext<ArtifactsStateModel>, action: CreateInstanceArtifactAction) { + const state = getState(); + return this.componentInstanceService.addInstanceArtifact(action.payload.componentType, action.payload.componentId, action.payload.instanceId, action.payload.artifact) + .pipe(tap((resp: ArtifactModel) => { + switch (resp.artifactGroupType) { + case ArtifactGroupType.DEPLOYMENT: + patchState({ + deploymentArtifacts: [...state.deploymentArtifacts, resp] + }); + break; + case ArtifactGroupType.INFORMATION: + patchState({ + artifacts: [...state.artifacts, resp] + }); + break; + } + })); + } + + @Action(UpdateInstanceArtifactAction) + updateArtifact({getState, patchState}: StateContext<ArtifactsStateModel>, action: UpdateInstanceArtifactAction) { + const state = getState(); + return this.componentInstanceService.updateInstanceArtifact(action.payload.componentType, action.payload.componentId, action.payload.instanceId, action.payload.artifact) + .pipe(tap((resp: ArtifactModel) => { + switch (resp.artifactGroupType) { + case ArtifactGroupType.DEPLOYMENT: + // We cannot simply update the updated artifact state because updating a deployment ENV file may cause an update to his parent HEAT + // file. + // Just dispatch an action to refresh the deployment artifacts list + this.store.dispatch(new GetInstanceArtifactsByTypeAction(({ + componentType: action.payload.componentType, + componentId: action.payload.componentId, + instanceId: action.payload.instanceId, + artifactType: ArtifactGroupType.DEPLOYMENT + }))); + break; + case ArtifactGroupType.INFORMATION: + patchState({ + artifacts: this.updateInstanceArtifactState(state.artifacts, action.payload.artifact, resp) + }); + break; + } + })); + } + + @Action(DeleteInstanceArtifactAction) + deleteInstanceArtifact({getState, patchState}: StateContext<ArtifactsStateModel>, action: DeleteInstanceArtifactAction) { + const state = getState(); + return this.componentInstanceService. + deleteInstanceArtifact(action.payload.componentId, action.payload.componentType, action.payload.instanceId, action.payload.artifact.uniqueId, action.payload.artifact.artifactLabel) + .pipe(tap((resp: ArtifactModel) => { + switch (resp.artifactGroupType) { + case ArtifactGroupType.DEPLOYMENT: + patchState({ + deploymentArtifacts: state.deploymentArtifacts.filter(({uniqueId}) => uniqueId !== action.payload.artifact.uniqueId) + }); + break; + case ArtifactGroupType.INFORMATION: + patchState({ + artifacts: state.artifacts.filter(({uniqueId}) => uniqueId !== action.payload.artifact.uniqueId) + }); + break; + } + })); + } + + private updateInstanceArtifactState = (artifactsState: ArtifactModel[], artifactToUpdate: ArtifactModel, updatedArtifact: ArtifactModel) => { + const artifactToUpdateIndex = _.findIndex(artifactsState, (artifact) => { + return artifact.uniqueId === artifactToUpdate.uniqueId; + }); + const artifacts = Array.from(artifactsState); + artifacts[artifactToUpdateIndex] = updatedArtifact; + const ret = [...artifacts]; + return ret; + } + +} diff --git a/catalog-ui/src/app/ng2/store/states/workspace.state.ts b/catalog-ui/src/app/ng2/store/states/workspace.state.ts new file mode 100644 index 0000000000..eb8200f6e0 --- /dev/null +++ b/catalog-ui/src/app/ng2/store/states/workspace.state.ts @@ -0,0 +1,48 @@ +/** + * Created by ob0695 on 7/17/2018. + */ +import {State, Action, StateContext} from '@ngxs/store'; +import {UpdateIsDesigner, UpdateIsViewOnly} from "../actions/workspace.action"; +import {Selector} from "@ngxs/store"; + +export interface WorkspaceStateModel { + isViewOnly: boolean; + isDesigner: boolean; +} + +@State<WorkspaceStateModel>({ + name: 'workspace', + defaults: { + isViewOnly: false, + isDesigner: true + } +}) + +export class WorkspaceState { + + constructor(){} + + @Selector() static isViewOnly(state: WorkspaceStateModel):boolean { + return state.isViewOnly; + } + @Selector() static isDesigner(state: WorkspaceStateModel): boolean { + return state.isDesigner; + } + + @Action(UpdateIsViewOnly) + updateIsViewOnly({getState, setState}: StateContext<WorkspaceStateModel>, action:UpdateIsViewOnly) { + const state = getState(); + setState({ + ...state, + isViewOnly: action.isViewOnly + }); + } + + @Action(UpdateIsDesigner) + updateIsDesigner({getState, patchState}: StateContext<WorkspaceStateModel>, action:UpdateIsDesigner) { + const state = getState(); + patchState({ + isDesigner: action.isDesigner + }); + } +}
\ No newline at end of file |