@finos/legend-application-studio
Version:
Legend Studio application core
133 lines • 11.5 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
/**
* 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 { useRef, useEffect } from 'react';
import { observer } from 'mobx-react-lite';
import { EntityDiffViewState } from '../../../stores/editor/editor-state/entity-diff-editor-state/EntityDiffViewState.js';
import { EntityDiffSideBarItem } from '../editor-group/diff-editor/EntityDiffView.js';
import { clsx, PanelLoadingIndicator, TruncatedGitMergeIcon, RefreshIcon, InfoCircleIcon, TimesIcon, PlusIcon, ExternalLinkSquareIcon, PanelContent, } from '@finos/legend-art';
import { ACTIVITY_MODE } from '../../../stores/editor/EditorConfig.js';
import { generateReviewRoute } from '../../../__lib__/LegendStudioNavigation.js';
import { LEGEND_STUDIO_TEST_ID } from '../../../__lib__/LegendStudioTesting.js';
import { flowResult } from 'mobx';
import { AuthorizableProjectAction, } from '@finos/legend-server-sdlc';
import { entityDiffSorter } from '../../../stores/editor/EditorSDLCState.js';
import { useEditorStore } from '../EditorStoreProvider.js';
import { useLegendStudioApplicationStore } from '../../LegendStudioFrameworkProvider.js';
import { formatDistanceToNow } from '@finos/legend-shared';
import { STUDIO_SDLC_USER_ERRORS } from '../../shared/StudioSDLCErrors.js';
export const WorkspaceReviewDiffs = observer(() => {
const editorStore = useEditorStore();
const workspaceReviewState = editorStore.workspaceReviewState;
const currentTabState = editorStore.tabManagerState.currentTab;
const changes = editorStore.changeDetectionState.aggregatedWorkspaceChanges;
const isSelectedDiff = (diff) => currentTabState instanceof EntityDiffViewState &&
diff.oldPath === currentTabState.fromEntityPath &&
diff.newPath === currentTabState.toEntityPath;
const openChange = (diff) => () => workspaceReviewState.openReviewChange(diff);
return (_jsxs("div", { className: "panel side-bar__panel workspace-review__diffs", children: [_jsxs("div", { className: "panel__header", children: [_jsxs("div", { className: "panel__header__title", children: [_jsx("div", { className: "panel__header__title__content", children: "CHANGES" }), _jsx("div", { className: "side-bar__panel__title__info", title: "All changes made in the workspace since the revision the workspace is created", children: _jsx(InfoCircleIcon, {}) })] }), _jsx("div", { className: "side-bar__panel__header__changes-count", "data-testid": LEGEND_STUDIO_TEST_ID.SIDEBAR_PANEL_HEADER__CHANGES_COUNT, children: changes.length })] }), _jsx(PanelContent, { children: changes.toSorted(entityDiffSorter).map((diff) => (_jsx(EntityDiffSideBarItem, { diff: diff, isSelected: isSelectedDiff(diff), openDiff: openChange(diff) }, diff.key))) })] }));
});
export const WorkspaceReview = observer(() => {
const editorStore = useEditorStore();
const applicationStore = useLegendStudioApplicationStore();
const workspaceReviewState = editorStore.workspaceReviewState;
const workspaceContainsSnapshotDependencies = editorStore.projectConfigurationEditorState.containsSnapshotDependencies;
const workspaceReview = workspaceReviewState.workspaceReview;
// Review Title
const reviewTitleInputRef = useRef(null);
const editReviewTitle = (event) => {
if (!workspaceReview) {
workspaceReviewState.setReviewTitle(event.target.value);
}
};
const isDispatchingAction = workspaceReviewState.isCreatingWorkspaceReview ||
workspaceReviewState.isFetchingCurrentWorkspaceReview ||
workspaceReviewState.isRefreshingWorkspaceChangesDetector ||
workspaceReviewState.isCommittingWorkspaceReview ||
workspaceReviewState.isClosingWorkspaceReview ||
workspaceReviewState.isRecreatingWorkspaceAfterCommittingReview;
const refresh = () => {
flowResult(workspaceReviewState.refreshWorkspaceChanges()).catch(applicationStore.alertUnhandledError);
flowResult(workspaceReviewState.fetchCurrentWorkspaceReview()).catch(applicationStore.alertUnhandledError);
};
const closeReview = () => {
workspaceReviewState.setReviewTitle('');
flowResult(workspaceReviewState.closeWorkspaceReview()).catch(applicationStore.alertUnhandledError);
};
// commit Review
const isCommitReviewDisabled = isDispatchingAction ||
Boolean(!workspaceReview) ||
workspaceContainsSnapshotDependencies ||
!workspaceReviewState.canMergeReview;
const commitReviewTitle = workspaceContainsSnapshotDependencies
? STUDIO_SDLC_USER_ERRORS.COMMIT_WORKSPACE_WITH_SNAPSHOT
: workspaceReviewState.sdlcState.isActiveProjectSandbox
? `Can't commit review: reviews are not allowed on sandbox projects`
: !workspaceReviewState.canMergeReview
? workspaceReviewState.sdlcState.unAuthorizedActionMessage(AuthorizableProjectAction.COMMIT_REVIEW)
: 'Commit review';
const commitReview = () => {
if (workspaceReview && !isDispatchingAction) {
editorStore.localChangesState.alertUnsavedChanges(() => {
workspaceReviewState.setReviewTitle('');
flowResult(workspaceReviewState.commitWorkspaceReview(workspaceReview)).catch(applicationStore.alertUnhandledError);
});
}
};
// create Review
const isCreateReviewDisabled = isDispatchingAction ||
Boolean(workspaceReview) ||
!workspaceReviewState.reviewTitle ||
workspaceContainsSnapshotDependencies ||
!workspaceReviewState.canCreateReview ||
workspaceReviewState.sdlcState.isActiveProjectSandbox;
const createReviewTitle = workspaceContainsSnapshotDependencies
? STUDIO_SDLC_USER_ERRORS.COMMIT_WORKSPACE_WITH_SNAPSHOT
: workspaceReviewState.sdlcState.isActiveProjectSandbox
? `Can't create review: reviews are not allowed on sandbox projects`
: !workspaceReviewState.canCreateReview
? workspaceReviewState.sdlcState.unAuthorizedActionMessage(AuthorizableProjectAction.SUBMIT_REVIEW)
: 'Create review';
const createReview = () => {
if (workspaceReviewState.reviewTitle &&
!workspaceReview &&
!isDispatchingAction) {
flowResult(workspaceReviewState.createWorkspaceReview(workspaceReviewState.reviewTitle)).catch(applicationStore.alertUnhandledError);
}
};
// since the review can be changed by other people, we can refresh it more proactively
// the diffs are caused by the current user though, so we should handle that as part
// of `syncWithWorkspace` for example; in case it is bad, user can click refresh to make it right again
useEffect(() => {
flowResult(workspaceReviewState.fetchCurrentWorkspaceReview()).catch(applicationStore.alertUnhandledError);
}, [applicationStore, workspaceReviewState]);
useEffect(() => {
if (editorStore.activeActivity === ACTIVITY_MODE.WORKSPACE_REVIEW) {
reviewTitleInputRef.current?.focus();
}
}, [editorStore.activeActivity]);
return (_jsxs("div", { className: "panel workspace-review", children: [_jsxs("div", { className: "panel__header side-bar__header", children: [_jsx("div", { className: "panel__header__title workspace-review__header__title", children: _jsx("div", { className: "panel__header__title__content side-bar__header__title__content", children: "REVIEW" }) }), _jsxs("div", { className: "panel__header__actions side-bar__header__actions", children: [_jsx("button", { className: clsx('panel__header__action side-bar__header__action workspace-review__refresh-btn', {
'workspace-review__refresh-btn--loading': workspaceReviewState.isRefreshingWorkspaceChangesDetector,
}), disabled: isDispatchingAction, onClick: refresh, tabIndex: -1, title: "Refresh", children: _jsx(RefreshIcon, {}) }), _jsx("button", { className: "panel__header__action side-bar__header__action workspace-review__close-btn", disabled: !workspaceReview || isDispatchingAction, onClick: closeReview, tabIndex: -1, title: "Close review", children: _jsx(TimesIcon, {}) })] })] }), _jsxs("div", { className: "panel__content side-bar__content", children: [_jsx(PanelLoadingIndicator, { isLoading: isDispatchingAction }), _jsxs("div", { className: "panel workspace-review", children: [!workspaceReview && (_jsx(_Fragment, { children: _jsxs("form", { className: "workspace-review__title", onSubmit: (event) => {
event.preventDefault();
}, children: [_jsx("div", { className: "workspace-review__title__content", children: _jsx("input", { className: "workspace-review__title__content__input input--dark", ref: reviewTitleInputRef, spellCheck: false, value: workspaceReviewState.reviewTitle, disabled: Boolean(workspaceReview), onChange: editReviewTitle, placeholder: "Title" }) }), _jsx("button", { className: clsx('btn--dark btn--sm', {
'btn--error': workspaceContainsSnapshotDependencies,
}), onClick: createReview, disabled: isCreateReviewDisabled, title: createReviewTitle, children: _jsx(PlusIcon, {}) })] }) })), workspaceReview && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "workspace-review__title", children: [_jsx("div", { className: "workspace-review__title__content", children: _jsx("div", { className: "workspace-review__title__content__input workspace-review__title__content__input--with-link", title: "See review detail", children: _jsxs("button", { className: "workspace-review__title__content__input__link", tabIndex: -1, onClick: () => applicationStore.navigationService.navigator.visitAddress(applicationStore.navigationService.navigator.generateAddress(generateReviewRoute(workspaceReview.projectId, workspaceReview.id))), children: [_jsx("span", { className: "workspace-review__title__content__input__link__review-name", children: workspaceReview.title }), _jsx("div", { className: "workspace-review__title__content__input__link__btn", children: _jsx(ExternalLinkSquareIcon, {}) })] }) }) }), _jsx("button", { className: clsx('btn--dark btn--sm workspace-review__merge-review-btn', { 'btn--error': workspaceContainsSnapshotDependencies }), onClick: commitReview, disabled: isCommitReviewDisabled, tabIndex: -1, title: commitReviewTitle, children: _jsx(TruncatedGitMergeIcon, {}) })] }), _jsx("div", { className: "workspace-review__title__content__review-status", children: `created ${formatDistanceToNow(workspaceReview.createdAt, {
includeSeconds: true,
addSuffix: true,
})}` })] })), _jsx(WorkspaceReviewDiffs, {})] })] })] }));
});
//# sourceMappingURL=WorkspaceReview.js.map