@finos/legend-application-studio
Version:
Legend Studio application core
354 lines • 41.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 { forwardRef, useEffect, useState } from 'react';
import { observer } from 'mobx-react-lite';
import { LEGEND_STUDIO_TEST_ID } from '../../../__lib__/LegendStudioTesting.js';
import { clsx, CustomSelectorInput, ShareIcon, PanelLoadingIndicator, ContextMenu, PencilIcon, InfoCircleIcon, TimesIcon, UsersIcon, UserIcon, ExternalLinkIcon, Dialog, PanelContent, Modal, ModalBody, ModalFooter, ModalFooterButton, MenuContentItem, MenuContent, PanelFormBooleanField, } from '@finos/legend-art';
import { PROJECT_OVERVIEW_ACTIVITY_MODE } from '../../../stores/editor/sidebar-state/ProjectOverviewState.js';
import { generateEditorRoute, generateViewProjectRoute, generateViewVersionRoute, generateReviewRoute, } from '../../../__lib__/LegendStudioNavigation.js';
import { flowResult } from 'mobx';
import { NewVersionType, WorkspaceType, areWorkspacesEquivalent, Review, ReviewState, Patch, } from '@finos/legend-server-sdlc';
import { useEditorStore } from '../EditorStoreProvider.js';
import { useApplicationStore } from '@finos/legend-application';
import { useLegendStudioApplicationStore } from '../../LegendStudioFrameworkProvider.js';
import { ActionState, assertErrorThrown, guaranteeNonNullable, LogEvent, } from '@finos/legend-shared';
import { DocumentationLink } from '@finos/legend-lego/application';
import { LEGEND_STUDIO_DOCUMENTATION_KEY } from '../../../__lib__/LegendStudioDocumentation.js';
import { LEGEND_STUDIO_APP_EVENT } from '../../../__lib__/LegendStudioEvent.js';
const ShareProjectModal = observer((props) => {
const { open, closeModal } = props;
const editorStore = useEditorStore();
const applicationStore = useLegendStudioApplicationStore();
const versions = editorStore.sdlcState.projectVersions;
const isDispatchingAction = editorStore.sdlcState.isFetchingProjectVersions;
const isFetchingProject = editorStore.sdlcState.isFetchingProject;
const [selectedVersion, setSelectedVersion] = useState();
const projectId = editorStore.sdlcState.activeProject.projectId;
const projectLink = selectedVersion
? applicationStore.navigationService.navigator.generateAddress(generateViewVersionRoute(projectId, selectedVersion.id.id))
: applicationStore.navigationService.navigator.generateAddress(generateViewProjectRoute(projectId));
const copyProjectElementLink = () => {
applicationStore.clipboardService
.copyTextToClipboard(projectLink)
.then(() => applicationStore.notificationService.notifySuccess('Copied project element link to clipboard'))
.catch(applicationStore.alertUnhandledError)
.finally(() => closeModal());
};
const renderOptions = versions.map((version) => ({
label: version.id.id,
value: version,
}));
const onSelectionChange = (val) => setSelectedVersion(val?.value);
return (_jsx(Dialog, { onClose: closeModal, open: open, children: _jsxs(Modal, { darkMode: !applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled, className: "modal--no-padding", children: [_jsx(PanelLoadingIndicator, { isLoading: isDispatchingAction }), _jsxs(ModalBody, { children: [_jsxs("div", { className: "project-overview__share-project__modal__info-entry", children: [_jsx("div", { className: "project-overview__share-project__modal__info-entry__title", children: "Version:" }), _jsx("div", { className: "project-overview__share-project__modal__info-entry__value", children: versions.length > 0 ? (_jsx("div", { className: "project-overview__share-project__modal__select", children: _jsx(CustomSelectorInput, { className: "setup-selector__input", options: renderOptions, disabled: isDispatchingAction || !versions.length, onChange: onSelectionChange, value: selectedVersion
? {
label: selectedVersion.id.id,
value: selectedVersion,
}
: null, darkMode: !applicationStore.layoutService
.TEMPORARY__isLightColorThemeEnabled }) })) : ('Project has only one version') })] }), _jsxs("div", { className: "project-overview__share-project__modal__info-entry", children: [_jsx("div", { className: "project-overview__share-project__modal__info-entry__title", children: "Link:" }), _jsx("div", { className: "project-overview__share-project__modal__info-entry__value", children: _jsx("a", { href: projectLink, target: "_blank", rel: "noopener noreferrer", children: projectLink }) })] })] }), _jsx(ModalFooter, { children: _jsx(ModalFooterButton, { className: "btn--wide", text: "Copy Link", disabled: isFetchingProject, onClick: copyProjectElementLink }) })] }) }));
});
const WorkspaceViewerContextMenu = observer(forwardRef(function WorkspaceViewerContextMenu(props, ref) {
const { workspace } = props;
const editorStore = useEditorStore();
const applicationStore = useApplicationStore();
const deleteWorkspace = applicationStore.guardUnhandledError(() => flowResult(editorStore.projectOverviewState.deleteWorkspace(workspace)));
return (_jsx(MenuContent, { ref: ref, children: _jsx(MenuContentItem, { onClick: deleteWorkspace, children: "Delete" }) }));
}));
const WorkspaceViewer = observer((props) => {
const { workspace } = props;
const editorStore = useEditorStore();
const applicationStore = useApplicationStore();
const isActive = areWorkspacesEquivalent(editorStore.sdlcState.activeWorkspace, workspace) &&
workspace.source ===
editorStore.sdlcState.activePatch?.patchReleaseVersionId.id;
const [isSelectedFromContextMenu, setIsSelectedFromContextMenu] = useState(false);
const onContextMenuOpen = () => setIsSelectedFromContextMenu(true);
const onContextMenuClose = () => setIsSelectedFromContextMenu(false);
return (_jsx(ContextMenu, { content: _jsx(WorkspaceViewerContextMenu, { workspace: workspace }), menuProps: { elevation: 7 }, onOpen: onContextMenuOpen, onClose: onContextMenuClose, children: _jsx("button", { className: clsx('side-bar__panel__item project-overview__item__link', {
'project-overview__item__link--selected-from-context-menu': isSelectedFromContextMenu && !isActive,
}, { 'project-overview__item__link--active': isActive }), tabIndex: -1, onClick: () => applicationStore.navigationService.navigator.visitAddress(applicationStore.navigationService.navigator.generateAddress(generateEditorRoute(workspace.projectId, editorStore.sdlcState.activePatch?.patchReleaseVersionId.id, workspace.workspaceId, workspace.workspaceType))), title: "See workspace", children: _jsxs("div", { className: "project-overview__item__link__content project-overview__workspace__viewer", children: [_jsx("div", { className: "project-overview__workspace__viewer-icon", children: workspace.workspaceType === WorkspaceType.GROUP ? (_jsx(UsersIcon, {})) : (_jsx(UserIcon, {})) }), _jsx("div", { className: "project-overview__item__link__content__name project-overview__workspace__viewer__label", children: workspace.workspaceId }), workspace.source && (_jsx("div", { className: "project-overview__workspace__viewer__source", children: `patch/${workspace.source}` }))] }) }) }));
});
const WorkspacesViewer = observer(() => {
const editorStore = useEditorStore();
const applicationStore = useApplicationStore();
const projectOverviewState = editorStore.projectOverviewState;
const workspaces = projectOverviewState.projectWorkspaces;
const isDispatchingAction = projectOverviewState.isDeletingWorkspace ||
projectOverviewState.isFetchingProjectWorkspaces;
// since this can be affected by other users, we refresh it more proactively
useEffect(() => {
flowResult(projectOverviewState.fetchProjectWorkspaces()).catch(applicationStore.alertUnhandledError);
}, [applicationStore, projectOverviewState]);
return (_jsxs("div", { className: "panel side-bar__panel project-overview__panel project-overview__workspaces", children: [_jsxs("div", { className: "panel__header", children: [_jsx("div", { className: "panel__header__title", children: _jsx("div", { className: "panel__header__title__content", children: PROJECT_OVERVIEW_ACTIVITY_MODE.WORKSPACES }) }), _jsx("div", { className: "side-bar__panel__header__changes-count", "data-testid": LEGEND_STUDIO_TEST_ID.SIDEBAR_PANEL_HEADER__CHANGES_COUNT, children: workspaces.length })] }), _jsxs("div", { className: "panel__content project-overview__panel__content", children: [_jsx(PanelLoadingIndicator, { isLoading: isDispatchingAction }), _jsx("div", { "data-testid": LEGEND_STUDIO_TEST_ID.PANEL_CONTENT_LIST, className: "panel__content__list", children: workspaces.map((workspace) => (_jsx(WorkspaceViewer, { workspace: workspace }, `${workspace.workspaceType}.${workspace.workspaceId}.${workspace.source}`))) })] })] }));
});
const ReleaseEditor = observer(() => {
const editorStore = useEditorStore();
const applicationStore = useLegendStudioApplicationStore();
const projectOverviewState = editorStore.projectOverviewState;
const commitedReviews = projectOverviewState.committedReviewsBetweenMostRecentVersionAndProjectLatest;
const isDispatchingAction = projectOverviewState.isFetchingLatestVersion ||
projectOverviewState.isFetchingCurrentProjectRevision ||
projectOverviewState.isCreatingVersion;
const { latestProjectVersion, currentProjectRevision } = projectOverviewState;
const revisionInput = projectOverviewState.releaseVersion;
const createMajorRelease = applicationStore.guardUnhandledError(() => flowResult(projectOverviewState.createVersion(NewVersionType.MAJOR)));
const createMinorRelease = applicationStore.guardUnhandledError(() => flowResult(projectOverviewState.createVersion(NewVersionType.MINOR)));
const createPatchRelease = applicationStore.guardUnhandledError(() => flowResult(projectOverviewState.createVersion(NewVersionType.PATCH)));
const changeNotes = (event) => revisionInput.setNotes(event.target.value);
const notFetchedLatestVersionAndCurrentRevision = latestProjectVersion === undefined || currentProjectRevision === undefined;
const isCurrentProjectVersionLatest = Boolean(latestProjectVersion) &&
latestProjectVersion?.revisionId === currentProjectRevision?.id;
const canCreateVersion = !isCurrentProjectVersionLatest &&
!isDispatchingAction &&
editorStore.sdlcServerClient.features.canCreateVersion &&
editorStore.sdlcState.canCreateVersion;
const disabledCreateVersionTitle = isCurrentProjectVersionLatest
? `Can't create version: project version not the latest`
: !editorStore.sdlcServerClient.features.canCreateVersion
? `Can't create version: current svn system does not support creating versions`
: !editorStore.sdlcState.canCreateVersion
? `Can't create version: You do not have the rights to create a version`
: undefined;
// since this can be affected by other users, we refresh it more proactively
useEffect(() => {
flowResult(projectOverviewState.fetchLatestProjectVersion()).catch(applicationStore.alertUnhandledError);
}, [
applicationStore,
editorStore.sdlcState.activePatch,
projectOverviewState,
]);
return (_jsxs("div", { className: "panel side-bar__panel project-overview__panel project-overview__release", children: [_jsx("div", { className: "panel__header", children: _jsx("div", { className: "panel__header__title", children: _jsx("div", { className: "panel__header__title__content", children: PROJECT_OVERVIEW_ACTIVITY_MODE.RELEASE }) }) }), _jsxs("div", { className: "panel__content project-overview__release__panel__content project-overview__release__content", children: [_jsx(PanelLoadingIndicator, { isLoading: isDispatchingAction }), _jsxs("div", { className: clsx('project-overview__release__editor project-overview__release__editor__project'), children: [_jsx("textarea", { className: "project-overview__release__editor__input input--dark", spellCheck: false, disabled: !canCreateVersion, value: revisionInput.notes, onChange: changeNotes, placeholder: "Release notes" }), _jsxs("div", { className: "project-overview__release__editor__actions", children: [_jsx("button", { className: "project-overview__release__editor__action btn--dark btn--caution", onClick: createMajorRelease, disabled: !canCreateVersion, title: disabledCreateVersionTitle ??
'Create a major release which comes with backward-incompatible features', children: "MAJOR" }), _jsx("button", { className: "project-overview__release__editor__action btn--dark", onClick: createMinorRelease, disabled: !canCreateVersion, title: disabledCreateVersionTitle ??
'Create a minor release which comes with backward-compatible features', children: "MINOR" }), _jsx("button", { className: "project-overview__release__editor__action btn--dark", onClick: createPatchRelease, disabled: !canCreateVersion, title: disabledCreateVersionTitle ??
'Create a patch release which comes with backward-compatible bug fixes', children: "PATCH" })] })] }), !notFetchedLatestVersionAndCurrentRevision && (_jsxs("div", { className: "project-overview__release__info", children: [_jsxs("div", { className: "panel project-overview__release__info__current-version__container", children: [_jsx("div", { className: "panel__header", children: _jsx("div", { className: "panel__header__title", children: _jsx("div", { className: "panel__header__title__content", children: "LATEST RELEASE" }) }) }), _jsxs(PanelContent, { children: [latestProjectVersion && (_jsx("div", { className: "project-overview__release__info__current-version", children: _jsx("button", { className: "project-overview__release__info__current-version__link", tabIndex: -1, onClick: () => applicationStore.navigationService.navigator.visitAddress(applicationStore.navigationService.navigator.generateAddress(generateViewVersionRoute(latestProjectVersion.projectId, latestProjectVersion.id.id))), title: "See version", children: _jsxs("div", { className: "project-overview__release__info__current-version__link__content", children: [_jsx("span", { className: "project-overview__release__info__current-version__link__content__name", children: latestProjectVersion.id.id }), _jsx("span", { className: "project-overview__release__info__current-version__link__content__info", children: latestProjectVersion.notes })] }) }) })), !latestProjectVersion && (_jsx("div", { className: "project-overview__release__info__current-version", children: _jsx("span", { className: "project-overview__release__info__current-version__no-version", children: "This project has no release" }) }))] })] }), _jsxs("div", { className: "panel project-overview__release__info__reviews", children: [_jsxs("div", { className: "panel__header", children: [_jsxs("div", { className: "panel__header__title", children: [_jsx("div", { className: "panel__header__title__content", children: "COMMITTED REVIEWS" }), _jsx("div", { className: "side-bar__panel__title__info", title: "All committed reviews in the project since the latest release", children: _jsx(InfoCircleIcon, {}) })] }), _jsx("div", { className: "side-bar__panel__header__changes-count", "data-testid": LEGEND_STUDIO_TEST_ID.SIDEBAR_PANEL_HEADER__CHANGES_COUNT, children: commitedReviews.length })] }), _jsx(PanelContent, { children: commitedReviews.map((review) => (_jsx("button", { className: "side-bar__panel__item workspace-updater__review__link", tabIndex: -1, onClick: () => applicationStore.navigationService.navigator.visitAddress(applicationStore.navigationService.navigator.generateAddress(generateReviewRoute(review.projectId, review.id))), title: "See review", children: _jsxs("div", { className: "workspace-updater__review", children: [_jsx("span", { className: "workspace-updater__review__name", children: review.title }), _jsx("span", { className: "workspace-updater__review__info", children: review.author.name })] }) }, review.id))) })] })] }))] })] }));
});
const PatchEditor = observer(() => {
const editorStore = useEditorStore();
const applicationStore = useLegendStudioApplicationStore();
const projectOverviewState = editorStore.projectOverviewState;
const [versionOptions] = useState(editorStore.sdlcState.projectVersions.map((v) => ({
label: v.id.id,
value: v.id.id,
})));
const [selectedVersionOption, setSelectedVersionOption] = useState(null);
const patches = projectOverviewState.patches;
const [selectedPatchOption, setSelectedPatchOption] = useState(null);
const [workspaceName, setWorkspaceName] = useState('');
const [isGroupWorkspace, setIsGroupWorkspace] = useState(true);
const [committedReviews, setCommittedReviews] = useState([]);
const [fetchSelectedPatchCommittedReviews] = useState(ActionState.create());
const onPatchOptionChange = async (val) => {
if ((val !== null || selectedPatchOption !== null) &&
(!val || !selectedPatchOption || val.value !== selectedPatchOption.value)) {
setSelectedPatchOption(val);
fetchSelectedPatchCommittedReviews.inProgress();
try {
if (val && val.value instanceof Patch) {
const reviews = await editorStore.sdlcServerClient.getReviews(projectOverviewState.sdlcState.activeProject.projectId, val.value.patchReleaseVersionId.id, {
state: ReviewState.COMMITTED,
});
setCommittedReviews(reviews.map((v) => Review.serialization.fromJson(v)));
}
else {
setCommittedReviews([]);
}
}
catch (error) {
assertErrorThrown(error);
editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error);
}
finally {
fetchSelectedPatchCommittedReviews.reset();
}
}
else {
setCommittedReviews([]);
}
};
const onVersionOptionChange = (val) => {
if ((val !== null || selectedVersionOption !== null) &&
(!val ||
!selectedVersionOption ||
val.value !== selectedVersionOption.value)) {
setSelectedVersionOption(val);
}
};
const createPatch = () => {
if (selectedVersionOption) {
flowResult(projectOverviewState.createPatch(selectedVersionOption.value, workspaceName, isGroupWorkspace ? WorkspaceType.GROUP : WorkspaceType.USER)).catch(applicationStore.alertUnhandledError);
}
};
const toggleGroupWorkspace = () => {
setIsGroupWorkspace(!isGroupWorkspace);
};
const changeWorkspaceName = (event) => setWorkspaceName(event.target.value);
const isDispatchingAction = projectOverviewState.isFetchingLatestVersion ||
projectOverviewState.isFetchingCurrentProjectRevision ||
projectOverviewState.isCreatingVersion;
const { latestProjectVersion, currentProjectRevision } = projectOverviewState;
const createPatchRelease = applicationStore.guardUnhandledError(() => flowResult(projectOverviewState.createPatchVersion(guaranteeNonNullable(selectedPatchOption).label)));
const isCurrentProjectVersionLatest = Boolean(latestProjectVersion) &&
latestProjectVersion?.revisionId === currentProjectRevision?.id;
const canCreateVersion = !isCurrentProjectVersionLatest &&
!isDispatchingAction &&
editorStore.sdlcServerClient.features.canCreateVersion;
const patchBlurb = `Releasing above mentioned version would delete the upstream branch created for doing this patch release. By doing so you won't be access any of the branches created for development for doing this patch release`;
useEffect(() => {
flowResult(projectOverviewState.fetchPatches()).catch(applicationStore.alertUnhandledError);
}, [
applicationStore.alertUnhandledError,
applicationStore.notificationService,
editorStore.sdlcServerClient,
editorStore.sdlcState.activeProject.projectId,
projectOverviewState,
]);
return (_jsxs("div", { className: "panel side-bar__panel project-overview__panel project-overview__patch", children: [_jsx("div", { className: "panel__header", children: _jsx("div", { className: "panel__header__title", children: _jsxs("div", { className: "panel__header__title__content", children: ["Create Patch", _jsx(DocumentationLink, { className: "project-overview__patch__documentation", documentationKey: LEGEND_STUDIO_DOCUMENTATION_KEY.QUESTION_WHAT_ARE_PROJECT_ROLES })] }) }) }), _jsxs("div", { className: "panel__content project-overview__panel__content", children: [_jsxs("div", { className: clsx('project-overview__patch__create', {
'project-overview__patch__create--progress': projectOverviewState.createPatchState.isInProgress,
}), children: [_jsx(PanelLoadingIndicator, { isLoading: projectOverviewState.createPatchState.isInProgress }), _jsx("div", { className: "project-overview__patch__content__progress-msg", children: projectOverviewState.createPatchState.message }), _jsx("div", { className: "panel__content__form", children: _jsxs("div", { className: "panel__content__form__section", children: [_jsx("div", { className: "panel__content__form__section__header__label", children: "Source Version" }), _jsx(CustomSelectorInput, { className: "project-overview__patch__source__version__selector", options: versionOptions, onChange: onVersionOptionChange, value: selectedVersionOption, placeholder: 'Select source version', isClearable: true, escapeClearsValue: true, darkMode: !applicationStore.layoutService
.TEMPORARY__isLightColorThemeEnabled })] }) }), _jsx("div", { className: "panel__content__form", children: _jsxs("div", { className: "panel__content__form__section", children: [_jsx("div", { className: "panel__content__form__section__header__label", children: "Workspace Name" }), _jsx("input", { className: "panel__content__form__section__input", title: "Workspace Name", spellCheck: false, value: workspaceName, placeholder: "Workspace Name", onChange: changeWorkspaceName })] }) }), _jsx("div", { className: "panel__content__form__section project-overview__patch__workspace__type__button", children: _jsx(PanelFormBooleanField, { name: "Group Workspace", prompt: "Group workspaces can be accessed by all users in the project", value: isGroupWorkspace, isReadOnly: false, update: toggleGroupWorkspace }) }), _jsx("div", { className: "panel__content__form__section__list__new-item__add", children: _jsx("button", { disabled: projectOverviewState.createPatchState.isInProgress ||
!editorStore.sdlcServerClient.features.canCreateVersion ||
!selectedVersionOption, onClick: () => createPatch(), className: "panel__content__form__section__list__new-item__add-btn btn btn--dark project-overview__patch__create__button", children: "Create" }) })] }), _jsxs("div", { className: "project-overview__patch__release", children: [_jsx("div", { className: "panel__header", children: _jsx("div", { className: "panel__header__title", children: _jsx("div", { className: "panel__header__title__content", children: "Release Patch" }) }) }), _jsxs("div", { className: "project-overview__patch__release", children: [_jsx(PanelLoadingIndicator, { isLoading: isDispatchingAction }), _jsxs(_Fragment, { children: [_jsx("div", { className: "panel__content__form", children: _jsxs("div", { className: "panel__content__form__section", children: [_jsx("div", { className: "panel__content__form__section__header__label", children: "Patch" }), _jsx(CustomSelectorInput, { className: "project-overview__patch__source__version__selector", options: patches.map((p) => ({
label: p.patchReleaseVersionId.id,
value: p,
})), onChange: (val) => {
onPatchOptionChange(val).catch(applicationStore.alertUnhandledError);
}, value: selectedPatchOption, placeholder: 'Select patch you want to release', isClearable: true, escapeClearsValue: true, darkMode: !applicationStore.layoutService
.TEMPORARY__isLightColorThemeEnabled })] }) }), _jsx("div", { className: "project-overview__patch__release__content", children: patchBlurb }), _jsx("div", { className: "panel__content__form__section__list__new-item__add", children: _jsx("button", { className: "panel__content__form__section__list__new-item__add-btn btn btn--dark project-overview__patch__release__button", onClick: createPatchRelease, disabled: !canCreateVersion && !selectedPatchOption, title: 'Create a patch release', children: "Release" }) })] })] })] }), _jsx("div", { className: "project-overview__release__info", children: _jsxs("div", { className: "panel project-overview__release__info__reviews", children: [_jsxs("div", { className: "panel__header", children: [_jsxs("div", { className: "panel__header__title", children: [_jsx("div", { className: "panel__header__title__content", children: "COMMITTED REVIEWS" }), _jsx("div", { className: "side-bar__panel__title__info", title: "All committed reviews in the patch since it got 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: committedReviews.length })] }), _jsx(PanelContent, { children: committedReviews.map((review) => (_jsx("button", { className: "side-bar__panel__item workspace-updater__review__link", tabIndex: -1, onClick: () => applicationStore.navigationService.navigator.visitAddress(applicationStore.navigationService.navigator.generateAddress(generateReviewRoute(review.projectId, review.id))), title: "See review", children: _jsxs("div", { className: "workspace-updater__review", children: [_jsx("span", { className: "workspace-updater__review__name", children: review.title }), _jsx("span", { className: "workspace-updater__review__info", children: review.author.name })] }) }, review.id))) })] }) })] })] }));
});
const VersionsViewer = observer(() => {
const editorStore = useEditorStore();
const applicationStore = useLegendStudioApplicationStore();
const versions = editorStore.sdlcState.projectVersions;
const isDispatchingAction = editorStore.sdlcState.isFetchingProjectVersions;
// since this can be affected by other users, we refresh it more proactively
useEffect(() => {
flowResult(editorStore.sdlcState.fetchProjectVersions()).catch(applicationStore.alertUnhandledError);
}, [applicationStore, editorStore]);
return (_jsxs("div", { className: "panel side-bar__panel project-overview__panel project-overview__versions", children: [_jsxs("div", { className: "panel__header", children: [_jsx("div", { className: "panel__header__title", children: _jsx("div", { className: "panel__header__title__content", children: PROJECT_OVERVIEW_ACTIVITY_MODE.VERSIONS }) }), _jsx("div", { className: "side-bar__panel__header__changes-count", "data-testid": LEGEND_STUDIO_TEST_ID.SIDEBAR_PANEL_HEADER__CHANGES_COUNT, children: versions.length })] }), _jsxs("div", { className: "panel__content project-overview__panel__content", children: [_jsx(PanelLoadingIndicator, { isLoading: isDispatchingAction }), _jsx("div", { className: "panel__content__list", children: versions.map((version) => (_jsx("button", { className: "side-bar__panel__item project-overview__item__link", tabIndex: -1, onClick: () => applicationStore.navigationService.navigator.visitAddress(applicationStore.navigationService.navigator.generateAddress(generateViewVersionRoute(version.projectId, version.id.id))), title: "See version", children: _jsxs("div", { className: "project-overview__item__link__content", children: [_jsx("span", { className: "project-overview__item__link__content__name", children: version.id.id }), _jsx("span", { className: "project-overview__item__link__content__info", children: version.notes })] }) }, version.id.id))) })] })] }));
});
const OverviewViewer = observer(() => {
const editorStore = useEditorStore();
const applicationStore = useApplicationStore();
const projectOverviewState = editorStore.projectOverviewState;
const sdlcState = editorStore.sdlcState;
const initialName = sdlcState.currentProject?.name ?? '';
const initialDescription = sdlcState.currentProject?.description ?? '';
const initialTags = sdlcState.currentProject?.tags ?? [];
const isDispatchingAction = projectOverviewState.updatingProjectState.isInProgress;
const [projectIdentifier, setProjectIdentifier] = useState(initialName);
const [description, setDescription] = useState(initialDescription);
const [itemValue, setItemValue] = useState('');
const [tagsArray, setTagsArray] = useState(initialTags);
const changeDescription = (event) => {
setDescription(event.target.value);
};
const changeProjectIdentifier = (event) => setProjectIdentifier(event.target.value);
// NOTE: `showEditInput` is either boolean (to hide/show the add value button) or a number (index of the item being edited)
const [showEditInput, setShowEditInput] = useState(false);
const showAddItemInput = () => setShowEditInput(true);
const showEditItemInput = (value, idx) => () => {
setItemValue(value);
setShowEditInput(idx);
};
const hideAddOrEditItemInput = () => {
setShowEditInput(false);
setItemValue('');
};
const changeItemInputValue = (event) => setItemValue(event.target.value);
const addValue = () => {
if (itemValue && !tagsArray.includes(itemValue)) {
setTagsArray([...tagsArray, itemValue]);
}
hideAddOrEditItemInput();
};
const updateValue = (idx) => () => {
if (itemValue && !tagsArray.includes(itemValue)) {
tagsArray[idx] = itemValue;
setTagsArray(tagsArray);
hideAddOrEditItemInput();
}
};
const deleteValue = (idx) => () => {
const tags = [...tagsArray];
tags.splice(idx, 1);
setTagsArray(tags);
// Since we keep track of the value currently being edited using the index, we have to account for it as we delete entry
if (typeof showEditInput === 'number' && showEditInput > idx) {
setShowEditInput(showEditInput - 1);
}
};
const handleUpdate = (event) => {
event.preventDefault();
flowResult(projectOverviewState.updateProject(projectIdentifier, description, tagsArray)).catch(applicationStore.alertUnhandledError);
};
return (_jsxs("div", { className: "panel side-bar__panel project-overview__panel project-overview__overview", children: [_jsxs("div", { className: "panel__header", children: [_jsx("div", { className: "panel__header__title", children: _jsx("div", { className: "panel__header__title__content", children: PROJECT_OVERVIEW_ACTIVITY_MODE.OVERVIEW }) }), _jsx("div", { className: "panel__header__actions", children: _jsx("button", { className: "panel__header__action project-overview__update-btn", onClick: handleUpdate, title: "Update Project", tabIndex: -1, children: _jsx("div", { className: "project-overview__update-btn__label", children: _jsx("div", { className: "project-overview__update-btn__label__title", children: "Update" }) }) }) })] }), _jsxs("div", { className: "panel__content project-overview__panel__content", children: [_jsx(PanelLoadingIndicator, { isLoading: isDispatchingAction }), _jsx("div", { className: "panel__content__form", children: _jsxs("div", { className: "panel__content__form__section", children: [_jsx("div", { className: "panel__content__form__section__header__label", children: "Project Name" }), _jsx("input", { className: "panel__content__form__section__input", title: "Project Name", spellCheck: false, value: projectIdentifier, onChange: changeProjectIdentifier })] }) }), _jsx("div", { className: "panel__content__form", children: _jsxs("div", { className: "panel__content__form__section", children: [_jsx("div", { className: "panel__content__form__section__header__label", children: "Description" }), _jsx("div", { className: "panel__content__form__section__header__prompt", children: "Description of the project" }), _jsx("textarea", { className: "panel__content__form__section__textarea", title: "PROJECT DESCRIPTION", spellCheck: false, value: description, onChange: changeDescription })] }) }), _jsx("div", { className: "panel__content__form", children: _jsxs("div", { className: "panel__content__form__section", children: [_jsx("div", { className: "panel__content__form__section__header__label", children: "Tags" }), _jsx("div", { className: "panel__content__form__section__header__prompt", children: "List of annotations to categorize projects" }), _jsx("div", { className: "panel__content__form__section__list" }), _jsxs("div", { className: "panel__content__form__section__list__items", "data-testid": LEGEND_STUDIO_TEST_ID.PANEL_CONTENT_FORM_SECTION_LIST_ITEMS, children: [tagsArray.map((value, idx) => (
// NOTE: since the value must be unique, we will use it as the key
_jsx("div", { className: showEditInput === idx
? 'panel__content__form__section__list__new-item'
: 'panel__content__form__section__list__item', children: showEditInput === idx ? (_jsxs(_Fragment, { children: [_jsx("input", { className: "panel__content__form__section__input panel__content__form__section__list__new-item__input", spellCheck: false, value: itemValue, onChange: changeItemInputValue }), _jsxs("div", { className: "panel__content__form__section__list__new-item__actions", children: [_jsx("button", { className: "panel__content__form__section__list__new-item__add-btn btn btn--dark", disabled: tagsArray.includes(itemValue), onClick: updateValue(idx), tabIndex: -1, children: "Save" }), _jsx("button", { className: "panel__content__form__section__list__new-item__cancel-btn btn btn--dark", onClick: hideAddOrEditItemInput, tabIndex: -1, children: "Cancel" })] })] })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: "panel__content__form__section__list__item__value", children: value }), _jsxs("div", { className: "panel__content__form__section__list__item__actions", children: [_jsx("button", { className: "panel__content__form__section__list__item__edit-btn", onClick: showEditItemInput(value, idx), tabIndex: -1, children: _jsx(PencilIcon, {}) }), _jsx("button", { className: "panel__content__form__section__list__item__remove-btn", onClick: deleteValue(idx), tabIndex: -1, children: _jsx(TimesIcon, {}) })] })] })) }, value))), showEditInput === true && (_jsxs("div", { className: "panel__content__form__section__list__new-item", children: [_jsx("input", { className: "panel__content__form__section__input panel__content__form__section__list__new-item__input", spellCheck: false, value: itemValue, title: "TAG INPUT", onChange: changeItemInputValue }), _jsxs("div", { className: "panel__content__form__section__list__new-item__actions", children: [_jsx("button", { className: "panel__content__form__section__list__new-item__add-btn btn btn--dark", disabled: tagsArray.includes(itemValue), onClick: addValue, tabIndex: -1, children: "Save" }), _jsx("button", { className: "panel__content__form__section__list__new-item__cancel-btn btn btn--dark", onClick: hideAddOrEditItemInput, tabIndex: -1, children: "Cancel" })] })] }))] }), showEditInput !== true && (_jsx("div", { className: "panel__content__form__section__list__new-item__add", children: _jsx("button", { className: "panel__content__form__section__list__new-item__add-btn btn btn--dark", onClick: showAddItemInput, tabIndex: -1, children: "Add Value" }) }))] }) })] })] }));
});
export const ProjectOverviewActivityBar = observer(() => {
const editorStore = useEditorStore();
const projectOverviewState = editorStore.projectOverviewState;
const isInEmbeddedMode = editorStore.projectConfigurationEditorState.isInEmbeddedMode;
const changeActivity = (activity) => () => projectOverviewState.setActivityMode(activity);
const activities = [
{ mode: PROJECT_OVERVIEW_ACTIVITY_MODE.OVERVIEW, title: 'Overview' },
{
mode: PROJECT_OVERVIEW_ACTIVITY_MODE.RELEASE,
title: 'Release',
},
{ mode: PROJECT_OVERVIEW_ACTIVITY_MODE.VERSIONS, title: 'Versions' },
{ mode: PROJECT_OVERVIEW_ACTIVITY_MODE.WORKSPACES, title: 'Workspaces' },
{ mode: PROJECT_OVERVIEW_ACTIVITY_MODE.PATCH, title: 'Patch' },
]
.filter((activity) => Boolean(activity))
.filter((act) =>
// releasing not supported in embedded mode
!(act.mode === PROJECT_OVERVIEW_ACTIVITY_MODE.RELEASE &&
isInEmbeddedMode));
return (_jsx("div", { "data-testid": LEGEND_STUDIO_TEST_ID.PROJECT_OVERVIEW__ACTIVITY_BAR, className: "project-overview__activity-bar", children: _jsx("div", { className: "project-overview__activity-bar__items", children: activities.map((activity) => (_jsx("div", { className: clsx('project-overview__activity-bar__item', {
'project-overview__activity-bar__item--active': activity.mode === projectOverviewState.activityMode,
}), onClick: changeActivity(activity.mode), tabIndex: -1, title: activity.title, children: _jsx("div", { className: "project-overview__activity-bar__item-mode", children: activity.mode }) }, activity.mode))) }) }));
});
export const ProjectOverview = observer(() => {
const editorStore = useEditorStore();
const applicationStore = useApplicationStore();
const [openShareModal, setOpenShareModal] = useState(false);
const showShareModal = () => setOpenShareModal(true);
const hideShareModal = () => setOpenShareModal(false);
const projectOverviewState = editorStore.projectOverviewState;
const openProjectWebUrl = () => applicationStore.navigationService.navigator.visitAddress(editorStore.sdlcState.activeProject.webUrl);
const renderOverview = () => {
switch (projectOverviewState.activityMode) {
case PROJECT_OVERVIEW_ACTIVITY_MODE.OVERVIEW:
return _jsx(OverviewViewer, {});
case PROJECT_OVERVIEW_ACTIVITY_MODE.RELEASE:
return _jsx(ReleaseEditor, {});
case PROJECT_OVERVIEW_ACTIVITY_MODE.VERSIONS:
return _jsx(VersionsViewer, {});
case PROJECT_OVERVIEW_ACTIVITY_MODE.WORKSPACES:
return _jsx(WorkspacesViewer, {});
case PROJECT_OVERVIEW_ACTIVITY_MODE.PATCH:
return _jsx(PatchEditor, {});
default:
return null;
}
};
return (_jsxs("div", { className: "panel project-overview", children: [_jsxs("div", { className: "panel__header side-bar__header", children: [_jsx("div", { className: "panel__header__title", children: _jsx("div", { className: "panel__header__title__content side-bar__header__title__content", children: "PROJECT" }) }), _jsxs("div", { className: "panel__header__actions side-bar__header__actions", children: [_jsx("button", { className: "panel__header__action side-bar__header__action", disabled: !editorStore.sdlcState.currentProject, title: "Share...", onClick: showShareModal, children: _jsx(ShareIcon, {}) }), _jsx("button", { className: "panel__header__action side-bar__header__action", disabled: !editorStore.sdlcState.currentProject, onClick: openProjectWebUrl, tabIndex: -1, title: "Go to project in underlying VCS system", children: _jsx(ExternalLinkIcon, {}) })] })] }), _jsxs("div", { className: "panel__content side-bar__content project-overview__content", children: [_jsx(ProjectOverviewActivityBar, {}), renderOverview()] }), editorStore.sdlcState.currentProject && (_jsx(ShareProjectModal, { open: openShareModal, closeModal: hideShareModal }))] }));
});
//# sourceMappingURL=ProjectOverview.js.map