UNPKG

@finos/legend-application-studio

Version:
291 lines 15.4 kB
/** * Copyright (c) 2020-present, Goldman Sachs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { action, makeObservable, flowResult, observable, flow, computed, } from 'mobx'; import { LEGEND_STUDIO_APP_EVENT } from '../../../__lib__/LegendStudioEvent.js'; import { LogEvent, assertErrorThrown, assertNonNullable, guaranteeNonNullable, } from '@finos/legend-shared'; import { EntityDiffViewState } from '../editor-state/entity-diff-editor-state/EntityDiffViewState.js'; import { SPECIAL_REVISION_ALIAS } from '../editor-state/entity-diff-editor-state/EntityDiffEditorState.js'; import { generateSetupRoute } from '../../../__lib__/LegendStudioNavigation.js'; import { EntityDiff, Review, ReviewState, RevisionAlias, AuthorizableProjectAction, isProjectSandbox, } from '@finos/legend-server-sdlc'; import { ActionAlertActionType } from '@finos/legend-application'; export class WorkspaceReviewState { editorStore; sdlcState; reviewTitle = ''; committedReviewsBetweenWorkspaceBaseAndProjectLatest = []; workspaceReview; isUpdatingWorkspace = false; isRefreshingWorkspaceUpdater = false; isFetchingCurrentWorkspaceReview = false; isRefreshingWorkspaceChangesDetector = false; isClosingWorkspaceReview = false; isCreatingWorkspaceReview = false; isCommittingWorkspaceReview = false; isRecreatingWorkspaceAfterCommittingReview = false; constructor(editorStore, sdlcState) { makeObservable(this, { reviewTitle: observable, committedReviewsBetweenWorkspaceBaseAndProjectLatest: observable, workspaceReview: observable, isUpdatingWorkspace: observable, isRefreshingWorkspaceUpdater: observable, isFetchingCurrentWorkspaceReview: observable, isRefreshingWorkspaceChangesDetector: observable, isClosingWorkspaceReview: observable, isCreatingWorkspaceReview: observable, isCommittingWorkspaceReview: observable, isRecreatingWorkspaceAfterCommittingReview: observable, canCreateReview: computed, canMergeReview: computed, setReviewTitle: action, openReviewChange: action, refreshWorkspaceChanges: flow, fetchCurrentWorkspaceReview: flow, recreateWorkspaceAfterCommittingReview: flow, closeWorkspaceReview: flow, createWorkspaceReview: flow, commitWorkspaceReview: flow, }); this.editorStore = editorStore; this.sdlcState = sdlcState; } get canCreateReview() { return this.sdlcState.userCanPerformAction(AuthorizableProjectAction.SUBMIT_REVIEW); } get canMergeReview() { return this.sdlcState.userCanPerformAction(AuthorizableProjectAction.COMMIT_REVIEW); } setReviewTitle(val) { this.reviewTitle = val; } openReviewChange(diff) { const fromEntityGetter = (entityPath) => entityPath ? this.editorStore.changeDetectionState.workspaceBaseRevisionState.entities.find((e) => e.path === entityPath) : undefined; const toEntityGetter = (entityPath) => entityPath ? this.editorStore.changeDetectionState.workspaceLocalLatestRevisionState.entities.find((e) => e.path === entityPath) : undefined; const fromEntity = EntityDiff.shouldOldEntityExist(diff) ? guaranteeNonNullable(fromEntityGetter(diff.getValidatedOldPath()), `Can't find entity with path '${diff.oldPath}'`) : undefined; const toEntity = EntityDiff.shouldNewEntityExist(diff) ? guaranteeNonNullable(toEntityGetter(diff.getValidatedNewPath()), `Can't find entity with path '${diff.newPath}'`) : undefined; this.editorStore.tabManagerState.openTab(new EntityDiffViewState(this.editorStore, SPECIAL_REVISION_ALIAS.WORKSPACE_BASE, SPECIAL_REVISION_ALIAS.WORKSPACE_HEAD, diff.oldPath, diff.newPath, fromEntity, toEntity, fromEntityGetter, toEntityGetter)); } *refreshWorkspaceChanges() { const startTime = Date.now(); this.isRefreshingWorkspaceChangesDetector = true; try { // ======= (RE)START CHANGE DETECTION ======= this.editorStore.changeDetectionState.stop(); yield Promise.all([ this.sdlcState.buildWorkspaceLatestRevisionEntityHashesIndex(), this.sdlcState.buildWorkspaceBaseRevisionEntityHashesIndex(), ]); this.editorStore.changeDetectionState.start(); yield Promise.all([ this.editorStore.changeDetectionState.computeAggregatedProjectLatestChanges(true), this.editorStore.changeDetectionState.computeAggregatedWorkspaceChanges(true), ]); this.editorStore.applicationStore.logService.info(LogEvent.create(LEGEND_STUDIO_APP_EVENT.CHANGE_DETECTION_RESTART__SUCCESS), Date.now() - startTime, 'ms'); // ======= FINISHED (RE)START CHANGE DETECTION ======= } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error); this.editorStore.applicationStore.notificationService.notifyError(error); this.sdlcState.handleChangeDetectionRefreshIssue(error); } finally { this.isRefreshingWorkspaceChangesDetector = false; } } *fetchCurrentWorkspaceReview() { try { this.isFetchingCurrentWorkspaceReview = true; const currentWorkspaceRevision = (yield this.editorStore.sdlcServerClient.getRevision(this.sdlcState.activeProject.projectId, this.sdlcState.activeWorkspace, RevisionAlias.CURRENT)); const reviews = (yield this.editorStore.sdlcServerClient.getReviews(this.sdlcState.activeProject.projectId, this.sdlcState.activePatch?.patchReleaseVersionId.id, { state: ReviewState.OPEN, revisionIds: [ currentWorkspaceRevision.id, currentWorkspaceRevision.id, ], limit: 1, })); const review = reviews.find((r) => r.workspaceId === this.sdlcState.activeWorkspace.workspaceId && r.workspaceType === this.sdlcState.activeWorkspace.workspaceType); if (reviews.length) { try { assertNonNullable(review, `Opened review associated with HEAD revision '${currentWorkspaceRevision.id}' of workspace '${this.sdlcState.activeWorkspace.workspaceType}' found, but the retrieved review does not belong to the workspace`); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.notificationService.notifyWarning(error.message); } } this.workspaceReview = review ? Review.serialization.fromJson(review) : undefined; } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error); this.editorStore.applicationStore.notificationService.notifyError(error); this.sdlcState.handleChangeDetectionRefreshIssue(error); } finally { this.isFetchingCurrentWorkspaceReview = false; } } *recreateWorkspaceAfterCommittingReview() { try { this.isRecreatingWorkspaceAfterCommittingReview = true; this.editorStore.applicationStore.alertService.setBlockingAlert({ message: 'Recreating workspace...', prompt: 'Please do not close the application', showLoading: true, }); yield this.editorStore.sdlcServerClient.createWorkspace(this.sdlcState.activeProject.projectId, this.sdlcState.activePatch?.patchReleaseVersionId.id, this.sdlcState.activeWorkspace.workspaceId, this.sdlcState.activeWorkspace.workspaceType); this.editorStore.applicationStore.navigationService.navigator.reload({ ignoreBlocking: true, }); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error); this.editorStore.applicationStore.notificationService.notifyError(error); } finally { this.editorStore.applicationStore.alertService.setBlockingAlert(undefined); this.isRecreatingWorkspaceAfterCommittingReview = false; } } *closeWorkspaceReview() { if (!this.workspaceReview) { return; } this.isClosingWorkspaceReview = true; try { yield this.editorStore.sdlcServerClient.rejectReview(this.sdlcState.activeProject.projectId, this.sdlcState.activePatch?.patchReleaseVersionId.id, this.workspaceReview.id); this.workspaceReview = undefined; } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error); this.editorStore.applicationStore.notificationService.notifyError(error); } finally { this.isClosingWorkspaceReview = false; } } /** * Below functions will be specific to properties on the project such as reviews, tags, etc.. */ *createWorkspaceReview(title, reviewDescription) { // NOTE: We will only allow having dependencies on snapshots in workspace, not in project // Therefore, we block creation of review and committing review containing a change // in dependency on snapshot versions if (this.editorStore.projectConfigurationEditorState .containsSnapshotDependencies) { this.editorStore.applicationStore.notificationService.notifyWarning(`Can't create review: workspace contains snapshot dependencies`); return; } if (isProjectSandbox(this.sdlcState.activeProject)) { this.editorStore.applicationStore.notificationService.notifyWarning(`Can't create review: Reviews for sandbox projects not suppoorted`); return; } this.isCreatingWorkspaceReview = true; try { const description = reviewDescription ?? `review from ${this.editorStore.applicationStore.config.appName} for workspace ${this.sdlcState.activeWorkspace.workspaceId}`; this.workspaceReview = Review.serialization.fromJson((yield this.editorStore.sdlcServerClient.createReview(this.sdlcState.activeProject.projectId, this.sdlcState.activePatch?.patchReleaseVersionId.id, { workspaceId: this.sdlcState.activeWorkspace.workspaceId, title, workspaceType: this.sdlcState.activeWorkspace.workspaceType, description, }))); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error); this.editorStore.applicationStore.notificationService.notifyError(error); } finally { this.isCreatingWorkspaceReview = false; } } *commitWorkspaceReview(review) { // NOTE: We will only allow having dependencies on snapshots in workspace, not in project // Therefore, we block creation of review and committing review containing a change // in dependency on snapshot versions if (this.editorStore.projectConfigurationEditorState .containsSnapshotDependencies) { this.editorStore.applicationStore.notificationService.notifyWarning(`Can't commit review: workspace contains snapshot dependencies`); return; } this.isCommittingWorkspaceReview = true; // check if the workspace is in conflict resolution mode try { const isInConflictResolutionMode = (yield flowResult(this.sdlcState.checkIfCurrentWorkspaceIsInConflictResolutionMode())); if (isInConflictResolutionMode) { this.editorStore.applicationStore.alertService.setBlockingAlert({ message: 'Workspace is in conflict resolution mode', prompt: 'Please refresh the application', }); return; } } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.notificationService.notifyWarning('Failed to check if current workspace is in conflict resolution mode'); return; } try { yield this.editorStore.sdlcServerClient.commitReview(this.sdlcState.activeProject.projectId, this.sdlcState.activePatch?.patchReleaseVersionId.id, review.id, { message: `${review.title} [review]` }); this.editorStore.applicationStore.alertService.setActionAlertInfo({ message: 'Committed review successfully', prompt: 'You can create a new workspace with the same name or leave for the start page', actions: [ { label: 'Create new workspace', handler: this.editorStore.applicationStore.guardUnhandledError(() => flowResult(this.recreateWorkspaceAfterCommittingReview())), type: ActionAlertActionType.PROCEED, }, { label: 'Leave', type: ActionAlertActionType.PROCEED, handler: () => { this.editorStore.applicationStore.navigationService.navigator.goToLocation(generateSetupRoute(this.editorStore.sdlcState.activeProject.projectId, this.sdlcState.activePatch?.patchReleaseVersionId.id), { ignoreBlocking: true, }); }, default: true, }, ], }); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error); this.editorStore.applicationStore.notificationService.notifyError(error); } finally { this.isCommittingWorkspaceReview = false; } } } //# sourceMappingURL=WorkspaceReviewState.js.map