UNPKG

@finos/legend-application-studio

Version:
120 lines 11.3 kB
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 { observer } from 'mobx-react-lite'; import { EntityDiffSideBarItem } from '../editor/editor-group/diff-editor/EntityDiffView.js'; import { clsx, PanelLoadingIndicator, TruncatedGitMergeIcon, RefreshIcon, TimesIcon, ArrowUpIcon, CheckIcon, InfoCircleIcon, PanelContent, } from '@finos/legend-art'; import { EntityDiffViewState } from '../../stores/editor/editor-state/entity-diff-editor-state/EntityDiffViewState.js'; import { LEGEND_STUDIO_TEST_ID } from '../../__lib__/LegendStudioTesting.js'; import { flowResult } from 'mobx'; import { ReviewState, EntityChangeType, getChangeTypeIconFromChange, } from '@finos/legend-server-sdlc'; import { entityDiffSorter } from '../../stores/editor/EditorSDLCState.js'; import { useProjectReviewerStore } from './ProjectReviewStoreProvider.js'; import { useEditorStore } from '../editor/EditorStoreProvider.js'; import { useApplicationStore } from '@finos/legend-application'; import { formatDistanceToNow } from '@finos/legend-shared'; import { SPECIAL_REVISION_ALIAS } from '../../stores/editor/editor-state/entity-diff-editor-state/EntityDiffEditorState.js'; import { ProjectConfigurationDiffEditorState } from '../../stores/editor/editor-state/diff-viewer-state/ProjectConfigurationDiffEditorState.js'; import { STUDIO_SDLC_USER_ERRORS } from '../shared/StudioSDLCErrors.js'; export const ProjectReviewerSideBar = observer(() => { const reviewStore = useProjectReviewerStore(); const editorStore = useEditorStore(); const applicationStore = useApplicationStore(); const workspaceContainsSnapshotDependencies = editorStore.projectConfigurationEditorState.containsSnapshotDependencies; const approvalString = reviewStore.approvalString; // Review infos const review = reviewStore.review; const currentUser = editorStore.sdlcServerClient.currentUser; let reviewStatus = ''; switch (review.state) { case ReviewState.OPEN: reviewStatus = `created ${formatDistanceToNow(review.createdAt, { includeSeconds: true, addSuffix: true, })} by ${review.author.name}`; break; case ReviewState.CLOSED: reviewStatus = review.closedAt ? `closed ${formatDistanceToNow(review.closedAt, { includeSeconds: true, addSuffix: true, })}` : 'review is closed'; break; case ReviewState.COMMITTED: reviewStatus = review.committedAt ? `committed ${formatDistanceToNow(review.committedAt, { includeSeconds: true, addSuffix: true, })}` : 'review is closed'; break; case ReviewState.UNKNOWN: reviewStatus = review.lastUpdatedAt ? `last updated ${formatDistanceToNow(review.lastUpdatedAt, { includeSeconds: true, addSuffix: true, })}` : 'review status is unknown'; break; default: } // Actions const isDispatchingAction = reviewStore.buildReviewReportState.isInProgress || reviewStore.approveState.isInProgress || reviewStore.closeState.isInProgress || reviewStore.commitState.isInProgress || reviewStore.reOpenState.isInProgress; const closeReview = applicationStore.guardUnhandledError(() => flowResult(reviewStore.closeReview())); const reOpenReview = applicationStore.guardUnhandledError(() => flowResult(reviewStore.reOpenReview())); const commitReview = applicationStore.guardUnhandledError(() => flowResult(reviewStore.commitReview())); const approveReview = applicationStore.guardUnhandledError(() => flowResult(reviewStore.approveReview())); const refresh = () => { reviewStore.refresh(); }; // Changes const changes = reviewStore.reviewReport?.diffs ?? []; const currentTabState = editorStore.tabManagerState.currentTab; const isSelectedDiff = (diff) => currentTabState instanceof EntityDiffViewState && diff.oldPath === currentTabState.fromEntityPath && diff.newPath === currentTabState.toEntityPath; const openChange = (diff) => () => reviewStore.openReviewChange(diff); const openConfiguration = () => { const diffs = reviewStore.reviewReport?.fromToProjectConfig; if (diffs) { const newTab = new ProjectConfigurationDiffEditorState(diffs[0], diffs[1], reviewStore.editorStore, SPECIAL_REVISION_ALIAS.WORKSPACE_BASE, SPECIAL_REVISION_ALIAS.WORKSPACE_HEAD); reviewStore.editorStore.tabManagerState.openTab(reviewStore.editorStore.tabManagerState.tabs.find((t) => t.match(newTab)) ?? newTab); } }; return (_jsxs("div", { className: "panel workspace-review__side-bar", children: [_jsxs("div", { className: "panel__header side-bar__header", children: [_jsx("div", { className: "panel__header__title workspace-review__side-bar__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: "panel__header__action side-bar__header__action workspace-review__close-btn", tabIndex: -1, title: "Retrieves latest changes from review", onClick: refresh, children: _jsx(RefreshIcon, {}) }), review.state !== ReviewState.COMMITTED && (_jsx("button", { className: "panel__header__action side-bar__header__action workspace-review__close-btn", disabled: isDispatchingAction || review.state === ReviewState.CLOSED, 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: [_jsxs("div", { className: "workspace-review__side-bar__review__info", children: [_jsx("div", { className: clsx('workspace-review__side-bar__review__info__content', { 'workspace-review__side-bar__review__info__content--closed': review.state === ReviewState.CLOSED, }, { 'workspace-review__side-bar__review__info__content--committed': review.state === ReviewState.COMMITTED, }), children: _jsx("div", { className: "workspace-review__side-bar__review__info__content__title", children: _jsx("span", { className: "workspace-review__side-bar__review__info__content__title__review-name", children: review.title }) }) }), review.state === ReviewState.CLOSED && (_jsx("button", { className: "workspace-review__side-bar__review__info__action btn--dark btn--sm", onClick: reOpenReview, disabled: isDispatchingAction, tabIndex: -1, title: "Reopen review", children: _jsx(ArrowUpIcon, {}) })), review.state === ReviewState.OPEN && (_jsxs(_Fragment, { children: [_jsx("button", { className: "btn--dark btn--sm", onClick: approveReview, // TODO: when we improve approval APIs we can know when to hide/disable this button altogether, right now the check is just to ensure nobody can self-approve disabled: isDispatchingAction || currentUser?.userId === review.author.name, tabIndex: -1, title: "Approve review", children: _jsx(CheckIcon, {}) }), _jsx("button", { className: clsx('btn--dark btn--sm workspace-review__side-bar__merge-btn', { 'btn--error': workspaceContainsSnapshotDependencies, }), onClick: commitReview, // TODO: when we improve approval APIs we can know when to hide/disable this button altogether disabled: isDispatchingAction || workspaceContainsSnapshotDependencies, tabIndex: -1, title: !workspaceContainsSnapshotDependencies ? 'Commit review' : STUDIO_SDLC_USER_ERRORS.COMMIT_WORKSPACE_WITH_SNAPSHOT, children: _jsx(TruncatedGitMergeIcon, {}) })] }))] }), approvalString && (_jsx("div", { className: "workspace-review__side-bar__review__info__content__status", children: approvalString })), _jsx("div", { className: "workspace-review__side-bar__review__info__content__status", children: reviewStatus }), _jsxs("div", { className: "panel side-bar__panel", 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 })] }), _jsxs(PanelContent, { children: [changes.toSorted(entityDiffSorter).map((diff) => (_jsx(EntityDiffSideBarItem, { diff: diff, isSelected: isSelectedDiff(diff), openDiff: openChange(diff) }, diff.key))), Boolean(reviewStore.reviewReport?.fromToProjectConfig) && (_jsxs("button", { className: clsx('side-bar__panel__item', { 'side-bar__panel__item--selected': editorStore.tabManagerState.currentTab instanceof ProjectConfigurationDiffEditorState, }), tabIndex: -1, title: `Project Configuration Modified`, onClick: openConfiguration, children: [_jsxs("div", { className: "diff-panel__item__info", children: [_jsx("span", { className: clsx('diff-panel__item__info-name', `diff-panel__item__info-name--${EntityChangeType.MODIFY.toLowerCase()}`), children: "config" }), _jsx("span", { className: "diff-panel__item__info-path", children: "project configuration" })] }), _jsx("div", { className: clsx('diff-panel__item__type', `diff-panel__item__type--${EntityChangeType.MODIFY.toLowerCase()}`), children: getChangeTypeIconFromChange(EntityChangeType.MODIFY) })] }))] })] })] })] })] })); }); //# sourceMappingURL=ProjectReviewSideBar.js.map