@finos/legend-application-studio
Version:
Legend Studio application core
206 lines • 22.3 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 { 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' }, slotProps: {
paper: {
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