@finos/legend-studio
Version:
288 lines (274 loc) • 10.1 kB
text/typescript
/**
* 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 type { EditorStore } from '../EditorStore.js';
import type { EditorSDLCState } from '../EditorSDLCState.js';
import { action, flowResult, makeAutoObservable } from 'mobx';
import {
type GeneratorFn,
type PlainObject,
assertErrorThrown,
LogEvent,
getNullableFirstElement,
} from '@finos/legend-shared';
import { generateSetupRoute } from '../LegendStudioRouter.js';
import {
type NewVersionType,
CreateVersionCommand,
ReviewState,
Revision,
RevisionAlias,
Version,
Workspace,
Review,
areWorkspacesEquivalent,
} from '@finos/legend-server-sdlc';
import { LEGEND_STUDIO_APP_EVENT } from '../LegendStudioAppEvent.js';
export enum PROJECT_OVERVIEW_ACTIVITY_MODE {
RELEASE = 'RELEASE',
OVERVIEW = 'OVERVIEW',
VERSIONS = 'VERSIONS',
WORKSPACES = 'WORKSPACES',
}
export class ProjectOverviewState {
editorStore: EditorStore;
sdlcState: EditorSDLCState;
activityMode = PROJECT_OVERVIEW_ACTIVITY_MODE.OVERVIEW;
releaseVersion: CreateVersionCommand;
committedReviewsBetweenMostRecentVersionAndProjectLatest: Review[] = [];
latestProjectVersion?: Version | null; // `undefined` if API is not yet called, `null` if fetched but no version exists
currentProjectRevision?: Revision | undefined;
projectWorkspaces: Workspace[] = [];
isCreatingVersion = false;
isFetchingProjectWorkspaces = false;
isDeletingWorkspace = false;
isUpdatingProject = false;
isFetchingLatestVersion = false;
isFetchingCurrentProjectRevision = false;
constructor(editorStore: EditorStore, sdlcState: EditorSDLCState) {
makeAutoObservable(this, {
editorStore: false,
sdlcState: false,
setActivityMode: action,
});
this.editorStore = editorStore;
this.sdlcState = sdlcState;
this.releaseVersion = new CreateVersionCommand();
}
setActivityMode(activityMode: PROJECT_OVERVIEW_ACTIVITY_MODE): void {
this.activityMode = activityMode;
}
*fetchProjectWorkspaces(): GeneratorFn<void> {
try {
this.isFetchingProjectWorkspaces = true;
this.projectWorkspaces = (
(yield this.editorStore.sdlcServerClient.getWorkspaces(
this.sdlcState.activeProject.projectId,
)) as PlainObject<Workspace>[]
).map((v) => Workspace.serialization.fromJson(v));
} catch (error) {
assertErrorThrown(error);
this.editorStore.applicationStore.log.error(
LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE),
error,
);
} finally {
this.isFetchingProjectWorkspaces = false;
}
}
*deleteWorkspace(workspace: Workspace): GeneratorFn<void> {
try {
this.isDeletingWorkspace = true;
yield this.editorStore.sdlcServerClient.deleteWorkspace(
this.sdlcState.activeProject.projectId,
workspace,
);
this.projectWorkspaces = this.projectWorkspaces.filter(
(w) => !areWorkspacesEquivalent(workspace, w),
);
// redirect to home page if current workspace is deleted
if (
areWorkspacesEquivalent(
this.editorStore.sdlcState.activeWorkspace,
workspace,
)
) {
this.editorStore.applicationStore.notifyWarning(
'Current workspace is deleted. Redirecting to home page',
);
this.editorStore.setIgnoreNavigationBlocking(true);
this.editorStore.applicationStore.navigator.goTo(
generateSetupRoute(
this.editorStore.sdlcState.activeProject.projectId,
),
);
}
} catch (error) {
assertErrorThrown(error);
this.editorStore.applicationStore.log.error(
LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE),
error,
);
} finally {
this.isDeletingWorkspace = false;
}
}
*updateProject(
name: string,
description: string,
tags: string[],
): GeneratorFn<void> {
try {
this.isUpdatingProject = true;
yield this.editorStore.sdlcServerClient.updateProject(
this.sdlcState.activeProject.projectId,
{
name,
description,
tags,
},
);
this.editorStore.applicationStore.notifySuccess(
`Project '${name}' is succesfully updated`,
);
yield flowResult(
this.sdlcState.fetchCurrentProject(
this.sdlcState.activeProject.projectId,
),
);
} catch (error) {
assertErrorThrown(error);
this.editorStore.applicationStore.notifyError(error);
} finally {
this.isUpdatingProject = false;
}
}
*fetchLatestProjectVersion(): GeneratorFn<void> {
try {
this.isFetchingLatestVersion = true;
// fetch latest version
const version = (yield this.editorStore.sdlcServerClient.getLatestVersion(
this.sdlcState.activeProject.projectId,
)) as PlainObject<Version> | undefined;
this.latestProjectVersion = version
? Version.serialization.fromJson(version)
: null;
// fetch current project revision and set release revision ID
this.currentProjectRevision = Revision.serialization.fromJson(
(yield this.editorStore.sdlcServerClient.getRevision(
this.sdlcState.activeProject.projectId,
undefined,
RevisionAlias.CURRENT,
)) as PlainObject<Revision>,
);
this.releaseVersion.setRevisionId(this.currentProjectRevision.id);
// fetch committed reviews between most recent version and project latest
if (this.latestProjectVersion) {
const latestProjectVersionRevision = Revision.serialization.fromJson(
(yield this.editorStore.sdlcServerClient.getRevision(
this.sdlcState.activeProject.projectId,
undefined,
this.latestProjectVersion.revisionId,
)) as PlainObject<Revision>,
);
// we find the review associated with the latest version revision, this usually exist, except in 2 cases:
// 1. the revision is somehow directly added to the branch by the user (in the case of `git`, user directly pushed to unprotected default branch)
// 2. the revision is the merged/comitted review revision (this usually happens for projects where fast forwarding merging is not default)
// in those case, we will get the time from the revision
const latestProjectVersionRevisionReviewObj = getNullableFirstElement(
(yield this.editorStore.sdlcServerClient.getReviews(
this.sdlcState.activeProject.projectId,
ReviewState.COMMITTED,
[latestProjectVersionRevision.id],
undefined,
undefined,
1,
)) as PlainObject<Review>[],
);
const latestProjectVersionRevisionReview =
latestProjectVersionRevisionReviewObj
? Review.serialization.fromJson(
latestProjectVersionRevisionReviewObj,
)
: undefined;
this.committedReviewsBetweenMostRecentVersionAndProjectLatest = (
(yield this.editorStore.sdlcServerClient.getReviews(
this.sdlcState.activeProject.projectId,
ReviewState.COMMITTED,
undefined,
latestProjectVersionRevisionReview?.committedAt ??
latestProjectVersionRevision.committedAt,
undefined,
undefined,
)) as PlainObject<Review>[]
)
.map((v) => Review.serialization.fromJson(v))
.filter(
(review) =>
!latestProjectVersionRevisionReview ||
review.id !== latestProjectVersionRevisionReview.id,
); // make sure to exclude the base review
} else {
this.committedReviewsBetweenMostRecentVersionAndProjectLatest = (
(yield this.editorStore.sdlcServerClient.getReviews(
this.sdlcState.activeProject.projectId,
ReviewState.COMMITTED,
undefined,
undefined,
undefined,
undefined,
)) as PlainObject<Review>[]
).map((v) => Review.serialization.fromJson(v));
}
} catch (error) {
assertErrorThrown(error);
this.editorStore.applicationStore.log.error(
LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE),
error,
);
} finally {
this.isFetchingLatestVersion = false;
}
}
*createVersion(versionType: NewVersionType): GeneratorFn<void> {
if (!this.editorStore.sdlcServerClient.features.canCreateVersion) {
this.editorStore.applicationStore.notifyError(
`Can't create version: not supported by SDLC server`,
);
return;
}
this.isCreatingVersion = true;
try {
this.releaseVersion.versionType = versionType;
this.releaseVersion.validate();
this.latestProjectVersion = Version.serialization.fromJson(
(yield this.editorStore.sdlcServerClient.createVersion(
this.sdlcState.activeProject.projectId,
CreateVersionCommand.serialization.toJson(this.releaseVersion),
)) as PlainObject<Version>,
);
yield flowResult(this.fetchLatestProjectVersion());
} catch (error) {
assertErrorThrown(error);
this.editorStore.applicationStore.log.error(
LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE),
error,
);
this.editorStore.applicationStore.notifyError(error);
} finally {
this.isCreatingVersion = false;
}
}
}