UNPKG

@finos/legend-application-studio

Version:
202 lines 22.2 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 { useState } from 'react'; import { observer } from 'mobx-react-lite'; import { clsx, Dialog, TimesIcon, PanelLoadingIndicator, PencilIcon, MarkdownTextViewer, Modal, PanelFormListItems, PanelFormTextField, PanelFormSection, PanelFormActions, PanelForm, PanelDivider, } from '@finos/legend-art'; import { LEGEND_STUDIO_TEST_ID } from '../../__lib__/LegendStudioTesting.js'; import { isNumber } from '@finos/legend-shared'; import { flowResult } from 'mobx'; import { useConditionedApplicationNavigationContext } from '@finos/legend-application'; import { LEGEND_STUDIO_DOCUMENTATION_KEY } from '../../__lib__/LegendStudioDocumentation.js'; import { LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY } from '../../__lib__/LegendStudioApplicationNavigationContext.js'; import { useLegendStudioApplicationStore } from '../LegendStudioFrameworkProvider.js'; import { useWorkspaceSetupStore } from './WorkspaceSetup.js'; import { DocumentationLink } from '@finos/legend-lego/application'; var CREATE_PROJECT_MODAL_TAB; (function (CREATE_PROJECT_MODAL_TAB) { CREATE_PROJECT_MODAL_TAB["CREATE"] = "CREATE"; CREATE_PROJECT_MODAL_TAB["IMPORT"] = "IMPORT"; })(CREATE_PROJECT_MODAL_TAB || (CREATE_PROJECT_MODAL_TAB = {})); const artifactIdPattern = new RegExp('^[a-z][a-z\\d_]*(?:-[a-z][a-z\\d_]*)*$'); const CreateNewProjectTab = observer(() => { const setupStore = useWorkspaceSetupStore(); const applicationStore = useLegendStudioApplicationStore(); const documentation = applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.CREATE_PROJECT); const allowCreatingNewProject = setupStore.sdlcServerClient.features.canCreateProject; const [projectName, setProjectName] = useState(''); const [groupId, setGroupId] = useState(''); const [artifactId, setArtifactId] = useState(''); const isArtfactIdInvalid = artifactId !== '' && !artifactIdPattern.test(artifactId); const [description, setDescription] = useState(''); const changeDescription = (event) => { setDescription(event.target.value); }; // tags const [tagValue, setTagValue] = useState(''); const [tagsArray, setTagsArray] = useState([]); // NOTE: `showEditInput` is either boolean (to hide/show the add value button) or a number (index of the item being edited) const [showEditTagValueInput, setShowEditTagValueInput] = useState(false); const showAddTagInput = () => setShowEditTagValueInput(true); const showEditTagInput = (value, idx) => () => { setTagValue(value); setShowEditTagValueInput(idx); }; const hideAddOrEditTagInput = () => { setShowEditTagValueInput(false); setTagValue(''); }; const changeTagInputValue = (event) => setTagValue(event.target.value); const addValue = () => { if (tagValue && !tagsArray.includes(tagValue)) { setTagsArray([...tagsArray, tagValue]); } hideAddOrEditTagInput(); }; const updateTag = (idx) => () => { if (tagValue && !tagsArray.includes(tagValue)) { tagsArray[idx] = tagValue; setTagsArray(tagsArray); hideAddOrEditTagInput(); } }; const deleteTag = (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 (isNumber(showEditTagValueInput) && showEditTagValueInput > idx) { setShowEditTagValueInput(showEditTagValueInput - 1); } }; const dispatchingActions = setupStore.createOrImportProjectState.isInProgress || setupStore.createWorkspaceState.isInProgress; const disableSubmit = dispatchingActions || !projectName || !artifactId || !groupId; const handleSubmit = () => { if (projectName && groupId && artifactId) { if (allowCreatingNewProject) { flowResult(setupStore.createProject(projectName, description, groupId, artifactId, tagsArray)).catch(applicationStore.alertUnhandledError); } } }; if (!allowCreatingNewProject) { return (_jsxs("div", { className: "workspace-setup__create-project-modal__form panel__content__form", children: [_jsx("div", { className: "panel__content__form__section workspace-setup__create-project-modal__form__unsupported", children: "SDLC server does not support creating new projects" }), documentation?.markdownText && (_jsx("div", { className: "panel__content__form__section", children: _jsx(MarkdownTextViewer, { value: documentation.markdownText }) }))] })); } return (_jsxs("form", { onSubmit: (event) => { event.preventDefault(); handleSubmit(); }, children: [_jsx(PanelLoadingIndicator, { isLoading: setupStore.createOrImportProjectState.isInProgress }), _jsxs(PanelForm, { className: "workspace-setup__create-project-modal__form", children: [documentation?.markdownText && (_jsx("div", { className: "panel__content__form__section", children: _jsx(MarkdownTextViewer, { value: documentation.markdownText }) })), _jsx(PanelFormTextField, { name: "Project Name", placeholder: "MyProject", value: projectName, update: (value) => setProjectName(value ?? ''), isReadOnly: false }), _jsxs(PanelFormSection, { children: [_jsx("div", { className: "panel__content__form__section__header__label", children: "Description" }), _jsx("textarea", { className: "panel__content__form__section__textarea", spellCheck: false, value: description, placeholder: "(optional)", onChange: changeDescription })] }), _jsx(PanelFormTextField, { name: "Group ID", prompt: "The domain for artifacts generated as part of the project build\n pipeline and published to an artifact repository", placeholder: applicationStore.config.options.projectCreationGroupIdSuggestion, value: groupId, update: (value) => setGroupId(value ?? '') }), _jsx(PanelFormTextField, { name: "Artifact ID", prompt: "The identifier (within the domain specified by group ID) for\n artifacts generated as part of the project build pipeline and\n published to an artifact repository", placeholder: "my-project", value: artifactId, update: (value) => setArtifactId(value ?? ''), errorMessage: isArtfactIdInvalid ? `Invalid artifactId: ${artifactId}. ArtifactId must follow the pattern that starts with a lowercase letter and can include lowercase letters, digits, underscores, and hyphens between segments.` : undefined }), _jsx(PanelFormListItems, { title: "Tags", prompt: "List of annotations to categorize projects", children: _jsxs("div", { "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: showEditTagValueInput === idx ? 'panel__content__form__section__list__new-item' : 'panel__content__form__section__list__item', children: showEditTagValueInput === idx ? (_jsxs(_Fragment, { children: [_jsx("input", { className: "panel__content__form__section__input panel__content__form__section__list__new-item__input", spellCheck: false, value: tagValue, onChange: changeTagInputValue }), _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(tagValue), onClick: updateTag(idx), tabIndex: -1, children: "Save" }), _jsx("button", { className: "panel__content__form__section__list__new-item__cancel-btn btn btn--dark", onClick: hideAddOrEditTagInput, 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: showEditTagInput(value, idx), tabIndex: -1, children: _jsx(PencilIcon, {}) }), _jsx("button", { className: "panel__content__form__section__list__item__remove-btn", onClick: deleteTag(idx), tabIndex: -1, children: _jsx(TimesIcon, {}) })] })] })) }, value))), showEditTagValueInput === 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: tagValue, onChange: changeTagInputValue }), _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(tagValue), onClick: addValue, tabIndex: -1, children: "Save" }), _jsx("button", { className: "panel__content__form__section__list__new-item__cancel-btn btn btn--dark", onClick: hideAddOrEditTagInput, tabIndex: -1, children: "Cancel" })] })] }))] }) }), showEditTagValueInput !== 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: showAddTagInput, tabIndex: -1, children: "Add Value" }) }))] }), _jsx(PanelFormActions, { children: _jsx("button", { disabled: disableSubmit, className: "btn btn--dark workspace-setup__create-project-modal__submit-btn", onClick: handleSubmit, children: "Create" }) })] })); }); const ImportProjectTab = observer(() => { const setupStore = useWorkspaceSetupStore(); const applicationStore = useLegendStudioApplicationStore(); const importProjectSuccessReport = setupStore.importProjectSuccessReport; const documentation = applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.IMPORT_PROJECT); const [projectIdentifier, setProjectIdentifier] = useState(''); const [groupId, setGroupId] = useState(''); const [artifactId, setArtifactId] = useState(''); const isArtfactIdInvalid = artifactId !== '' && !artifactIdPattern.test(artifactId); const [description, setDescription] = useState(''); const changeDescription = (event) => { setDescription(event.target.value); }; // tags const [tagValue, setTagValue] = useState(''); const [tagsArray, setTagsArray] = useState([]); // NOTE: `showEditInput` is either boolean (to hide/show the add value button) or a number (index of the item being edited) const [showEditTagValueInput, setShowEditTagValueInput] = useState(false); const showAddTagInput = () => setShowEditTagValueInput(true); const showEditTagInput = (value, idx) => () => { setTagValue(value); setShowEditTagValueInput(idx); }; const hideAddOrEditTagInput = () => { setShowEditTagValueInput(false); setTagValue(''); }; const changeTagInputValue = (event) => setTagValue(event.target.value); const addValue = () => { if (tagValue && !tagsArray.includes(tagValue)) { setTagsArray([...tagsArray, tagValue]); } hideAddOrEditTagInput(); }; const updateTag = (idx) => () => { if (tagValue && !tagsArray.includes(tagValue)) { tagsArray[idx] = tagValue; setTagsArray(tagsArray); hideAddOrEditTagInput(); } }; const deleteTag = (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 (isNumber(showEditTagValueInput) && showEditTagValueInput > idx) { setShowEditTagValueInput(showEditTagValueInput - 1); } }; const dispatchingActions = setupStore.createOrImportProjectState.isInProgress || setupStore.createWorkspaceState.isInProgress; const disableSubmit = dispatchingActions || !projectIdentifier || !artifactId || !groupId; const handleSubmit = () => { if (importProjectSuccessReport) { applicationStore.navigationService.navigator.visitAddress(importProjectSuccessReport.reviewUrl); } else { if (projectIdentifier && groupId && artifactId) { flowResult(setupStore.importProject(projectIdentifier, groupId, artifactId)).catch(applicationStore.alertUnhandledError); } } }; return (_jsxs("form", { onSubmit: (event) => { event.preventDefault(); handleSubmit(); }, children: [_jsx(PanelLoadingIndicator, { isLoading: setupStore.createOrImportProjectState.isInProgress }), _jsxs(PanelForm, { className: "workspace-setup__create-project-modal__form", children: [documentation?.markdownText && (_jsx(PanelFormSection, { children: _jsx(MarkdownTextViewer, { value: documentation.markdownText }) })), _jsx("div", { children: _jsx(PanelFormTextField, { name: "Project ID", prompt: "The ID of the project in the underlying version-control system", placeholder: "1234", value: projectIdentifier, update: (value) => setProjectIdentifier(value ?? ''), isReadOnly: Boolean(importProjectSuccessReport) }) }), _jsx(PanelDivider, {}), _jsxs(PanelFormSection, { children: [_jsx("div", { className: "panel__content__form__section__header__label", children: "Description" }), _jsx("textarea", { className: "panel__content__form__section__textarea", spellCheck: false, value: description, placeholder: "(optional)", onChange: changeDescription })] }), _jsx(PanelFormTextField, { name: "Group ID", prompt: "The domain for artifacts generated as part of the project build\n pipeline and published to an artifact repository", placeholder: applicationStore.config.options.projectCreationGroupIdSuggestion, value: groupId, update: (value) => setGroupId(value ?? ''), isReadOnly: Boolean(importProjectSuccessReport) }), _jsx(PanelFormTextField, { name: "Artifact ID", prompt: "The identifier (within the domain specified by group ID) for\n artifacts generated as part of the project build pipeline and\n published to an artifact repository", placeholder: "my-project", value: artifactId, update: (value) => setArtifactId(value ?? ''), isReadOnly: Boolean(importProjectSuccessReport), errorMessage: isArtfactIdInvalid ? `Invalid artifactId: ${artifactId}. ArtifactId must follow the pattern that starts with a lowercase letter and can include lowercase letters, digits, underscores, and hyphens between segments.` : undefined }), _jsx(PanelFormListItems, { title: "Tags", prompt: "List of annotations to categorize projects", children: _jsxs("div", { "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: showEditTagValueInput === idx ? 'panel__content__form__section__list__new-item' : 'panel__content__form__section__list__item', children: showEditTagValueInput === idx ? (_jsxs(_Fragment, { children: [_jsx("input", { className: "panel__content__form__section__input panel__content__form__section__list__new-item__input", spellCheck: false, value: tagValue, onChange: changeTagInputValue }), _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(tagValue), onClick: updateTag(idx), tabIndex: -1, children: "Save" }), _jsx("button", { className: "panel__content__form__section__list__new-item__cancel-btn btn btn--dark", onClick: hideAddOrEditTagInput, 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: showEditTagInput(value, idx), tabIndex: -1, children: _jsx(PencilIcon, {}) }), _jsx("button", { className: "panel__content__form__section__list__item__remove-btn", onClick: deleteTag(idx), tabIndex: -1, children: _jsx(TimesIcon, {}) })] })] })) }, value))), showEditTagValueInput === 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: tagValue, onChange: changeTagInputValue }), _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(tagValue), onClick: addValue, tabIndex: -1, children: "Save" }), _jsx("button", { className: "panel__content__form__section__list__new-item__cancel-btn btn btn--dark", onClick: hideAddOrEditTagInput, tabIndex: -1, children: "Cancel" })] })] }))] }) }), showEditTagValueInput !== 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: showAddTagInput, tabIndex: -1, children: "Add Value" }) })), Boolean(importProjectSuccessReport) && (_jsx("div", { className: "workspace-setup__create-project-modal__success", children: _jsxs("div", { className: "workspace-setup__create-project-modal__success__label", children: [_jsx("span", { className: "workspace-setup__create-project-modal__success__label__text", children: "The SDLC server has successfully registered your project. To complete the import, please commit the following" }), _jsx("a", { className: "workspace-setup__create-project-modal__success__label__link", href: importProjectSuccessReport?.reviewUrl, rel: "noopener noreferrer", target: "_blank", children: "review." })] }) }))] }), _jsx(PanelFormActions, { children: _jsx("button", { disabled: disableSubmit, className: "btn btn--dark workspace-setup__create-project-modal__submit-btn", onClick: handleSubmit, children: importProjectSuccessReport ? 'Review' : 'Import' }) })] })); }); export const CreateProjectModal = observer(() => { const setupStore = useWorkspaceSetupStore(); const applicationStore = setupStore.applicationStore; const allowCreatingNewProject = setupStore.sdlcServerClient.features.canCreateProject; const [selectedTab, setSelectedTab] = useState(allowCreatingNewProject ? CREATE_PROJECT_MODAL_TAB.CREATE : CREATE_PROJECT_MODAL_TAB.IMPORT); const closeModal = () => { setupStore.setShowCreateProjectModal(false); setupStore.setImportProjectSuccessReport(undefined); }; const switchTab = (val) => () => setSelectedTab(val); useConditionedApplicationNavigationContext(LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY.SETUP_CREATE_PROJECT_DIALOG, setupStore.showCreateProjectModal); return (_jsx(Dialog, { open: setupStore.showCreateProjectModal, onClose: closeModal, classes: { container: 'search-modal__container' }, PaperProps: { classes: { root: 'search-modal__inner-container' } }, children: _jsxs(Modal, { darkMode: !applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled, className: "workspace-setup__create-project-modal", children: [_jsx("div", { className: "workspace-setup__create-project-modal__header", children: _jsx("div", { className: "workspace-setup__create-project-modal__header__label", children: "Create Project" }) }), _jsxs("div", { className: "workspace-setup__create-project-modal__header__tabs", children: [_jsxs("button", { onClick: switchTab(CREATE_PROJECT_MODAL_TAB.CREATE), className: clsx('workspace-setup__create-project-modal__header__tab', { 'workspace-setup__create-project-modal__header__tab--active': selectedTab === CREATE_PROJECT_MODAL_TAB.CREATE, }), children: ["Create New Project", _jsx(DocumentationLink, { documentationKey: LEGEND_STUDIO_DOCUMENTATION_KEY.CREATE_PROJECT })] }), _jsxs("button", { onClick: switchTab(CREATE_PROJECT_MODAL_TAB.IMPORT), className: clsx('workspace-setup__create-project-modal__header__tab', { 'workspace-setup__create-project-modal__header__tab--active': selectedTab === CREATE_PROJECT_MODAL_TAB.IMPORT, }), children: ["Import Project", _jsx(DocumentationLink, { documentationKey: LEGEND_STUDIO_DOCUMENTATION_KEY.IMPORT_PROJECT })] })] }), _jsxs("div", { className: "workspace-setup__create-project-modal__content", children: [selectedTab === CREATE_PROJECT_MODAL_TAB.CREATE && (_jsx(CreateNewProjectTab, {})), selectedTab === CREATE_PROJECT_MODAL_TAB.IMPORT && (_jsx(ImportProjectTab, {}))] })] }) })); }); //# sourceMappingURL=CreateProjectModal.js.map