@finos/legend-studio
Version:
221 lines • 16.7 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } 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 { useEffect, useRef } from 'react';
import { LogEvent, prettyCONSTName, assertErrorThrown, guaranteeNonNullable, } from '@finos/legend-shared';
import { observer } from 'mobx-react-lite';
import { ProjectConfigurationEditorState, CONFIGURATION_EDITOR_TAB, } from '../../../../stores/editor-state/ProjectConfigurationEditorState.js';
import { compareLabelFn, clsx, CustomSelectorInput, PlusIcon, TimesIcon, CheckCircleIcon, ExclamationCircleIcon, ExternalLinkSquareIcon, } from '@finos/legend-art';
import { flowResult } from 'mobx';
import { ProjectDependency, } from '@finos/legend-server-sdlc';
import { useEditorStore } from '../../EditorStoreProvider.js';
import { ActionAlertActionType, ActionAlertType, useApplicationStore, } from '@finos/legend-application';
import { LEGEND_STUDIO_APP_EVENT } from '../../../../stores/LegendStudioAppEvent.js';
import { SNAPSHOT_VERSION_ALIAS, MASTER_SNAPSHOT_ALIAS, compareSemVerVersions, generateGAVCoordinates, } from '@finos/legend-server-depot';
const buildProjectOption = (project) => ({
label: project.coordinates,
value: project,
});
const ProjectStructureEditor = observer((props) => {
const { projectConfig, isReadOnly } = props;
const editorStore = useEditorStore();
const applicationStore = useApplicationStore();
const latestVersion = editorStore.projectConfigurationEditorState.latestProjectStructureVersion;
const currentProjectExtensionVersion = projectConfig.projectStructureVersion.extensionVersion ?? -1;
const latestProjectExtensionVersion = latestVersion?.extensionVersion ?? -1;
const isVersionOutdated = latestVersion &&
(latestVersion.version > projectConfig.projectStructureVersion.version ||
latestProjectExtensionVersion > currentProjectExtensionVersion);
const changeGroupId = (event) => {
if (!isReadOnly) {
projectConfig.setGroupId(event.target.value);
}
};
const changeArtifactId = (event) => {
if (!isReadOnly) {
projectConfig.setArtifactId(event.target.value);
}
};
const updateVersion = () => {
flowResult(editorStore.projectConfigurationEditorState.updateToLatestStructure()).catch(applicationStore.alertUnhandledError);
};
return (_jsxs("div", { className: "panel__content__lists", children: [_jsxs("div", { className: "project-configuration-editor__project__structure__version", children: [_jsxs("div", { className: "project-configuration-editor__project__structure__version__label", children: [_jsx("div", { className: "project-configuration-editor__project__structure__version__label__status", children: isVersionOutdated ? (_jsx(ExclamationCircleIcon, { className: "project-configuration-editor__project__structure__version__label__status--outdated", title: "Project structure is outdated" })) : (_jsx(CheckCircleIcon, { className: "project-configuration-editor__project__structure__version__label__status--up-to-date", title: "Project structure is up to date" })) }), _jsxs("div", { className: "project-configuration-editor__project__structure__version__label__text", children: ["PROJECT STRUCTURE VERSION", ' ', ` ${projectConfig.projectStructureVersion.fullVersion}`] })] }), isVersionOutdated && (_jsxs("button", { className: "project-configuration-editor__project__structure__version__update-btn", disabled: isReadOnly, onClick: updateVersion, tabIndex: -1, title: `Current project structure is outdated. Click to update to the latest version (v${latestVersion.fullVersion}})`, children: ["Update to version ", latestVersion.fullVersion] }))] }), _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: "Group ID" }), _jsx("div", { className: "panel__content__form__section__header__prompt", children: "The domain for artifacts generated as part of the project build pipeline and published to an artifact repository" }), _jsx("input", { className: "panel__content__form__section__input", spellCheck: false, disabled: isReadOnly, value: projectConfig.groupId, onChange: changeGroupId })] }) }), _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: "Artifact ID" }), _jsx("div", { className: "panel__content__form__section__header__prompt", children: "The identifier (within the domain specified by group ID) for artifacts generated as part of the project build pipeline and published to an artifact repository" }), _jsx("input", { className: "panel__content__form__section__input", spellCheck: false, disabled: isReadOnly, value: projectConfig.artifactId, onChange: changeArtifactId })] }) })] }));
});
const formatOptionLabel = (option) => (_jsxs("div", { className: "project-dependency-editor__label", children: [_jsx("div", { className: "project-dependency-editor__label__tag", children: option.value.projectId }), _jsx("div", { className: "project-dependency-editor__label__name", children: option.value.coordinates })] }));
const ProjectDependencyEditor = observer((props) => {
// init
const { projectDependency, deleteValue, isReadOnly } = props;
const editorStore = useEditorStore();
const applicationStore = useApplicationStore();
const projectSelectorRef = useRef(null);
const versionSelectorRef = useRef(null);
const configState = editorStore.projectConfigurationEditorState;
// project
const selectedProject = configState.projects.get(projectDependency.projectId);
const selectedProjectOption = selectedProject
? buildProjectOption(selectedProject)
: null;
const projectDisabled = !configState.associatedProjectsAndVersionsFetched ||
configState.isReadOnly;
const projectsOptions = Array.from(configState.projects.values())
.map(buildProjectOption)
.sort(compareLabelFn);
const onProjectSelectionChange = (val) => {
if ((val !== null || selectedProjectOption !== null) &&
(!val ||
!selectedProjectOption ||
val.value !== selectedProjectOption.value)) {
projectDependency.setProjectId(val?.value.coordinates ?? '');
if (val) {
projectDependency.setVersionId(val.value.latestVersion);
}
}
};
// version
const version = projectDependency.versionId;
const versions = selectedProject?.versions ?? [];
let versionOptions = versions
.slice()
.sort((v1, v2) => compareSemVerVersions(v2, v1))
.map((v) => ({ value: v, label: v }));
versionOptions = [
{ label: SNAPSHOT_VERSION_ALIAS, value: MASTER_SNAPSHOT_ALIAS },
...versionOptions,
];
const selectedVersionOption = versionOptions.find((v) => v.value === version) ?? null;
const versionDisabled = Boolean(!versions.length || !projectDependency.projectId.length) ||
!configState.associatedProjectsAndVersionsFetched ||
isReadOnly;
const onVersionSelectionChange = (val) => {
if ((val !== null || selectedVersionOption !== null) &&
(!val ||
!selectedVersionOption ||
val.value !== selectedVersionOption.value)) {
try {
projectDependency.setVersionId(val?.value ?? '');
}
catch (error) {
assertErrorThrown(error);
applicationStore.log.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error);
}
}
};
const openProject = () => {
if (!projectDependency.isLegacyDependency) {
const projectDependencyVersionId = projectDependency.versionId === MASTER_SNAPSHOT_ALIAS
? SNAPSHOT_VERSION_ALIAS
: projectDependency.versionId;
applicationStore.navigator.openNewWindow(`${applicationStore.config.baseUrl}view/archive/${generateGAVCoordinates(guaranteeNonNullable(projectDependency.groupId), guaranteeNonNullable(projectDependency.artifactId), projectDependencyVersionId)}`);
}
};
const projectSelectorPlaceholder = !projectDependency.projectId.length
? 'Choose project'
: versionDisabled
? 'No project version found. Please create a new one.'
: 'Select version';
return (_jsxs("div", { className: "project-dependency-editor", children: [_jsx(CustomSelectorInput, { className: "project-dependency-editor__selector", ref: projectSelectorRef, disabled: projectDisabled, options: projectsOptions, isClearable: true, escapeClearsValue: true, onChange: onProjectSelectionChange, value: selectedProjectOption, isLoading: configState.isFetchingAssociatedProjectsAndVersions, formatOptionLabel: formatOptionLabel, darkMode: true }), _jsx(CustomSelectorInput, { className: "project-dependency-editor__selector", ref: versionSelectorRef, options: versionOptions, isClearable: true, escapeClearsValue: true, onChange: onVersionSelectionChange, value: selectedVersionOption, disabled: versionDisabled, placeholder: projectSelectorPlaceholder, isLoading: editorStore.projectConfigurationEditorState
.isFetchingAssociatedProjectsAndVersions, darkMode: true }), _jsx("button", { className: "project-dependency-editor__visit-btn btn--dark btn--sm", disabled: projectDependency.isLegacyDependency ||
!selectedProject ||
!selectedVersionOption, onClick: openProject, tabIndex: -1, title: 'Open Project', children: _jsx(ExternalLinkSquareIcon, {}) }), _jsx("button", { className: "project-dependency-editor__remove-btn btn--dark btn--caution", disabled: isReadOnly, onClick: deleteValue, tabIndex: -1, title: 'Close', children: _jsx(TimesIcon, {}) })] }));
});
export const ProjectConfigurationEditor = observer(() => {
const editorStore = useEditorStore();
const applicationStore = useApplicationStore();
const configState = editorStore.getCurrentEditorState(ProjectConfigurationEditorState);
const sdlcState = editorStore.sdlcState;
const isReadOnly = editorStore.isInViewerMode;
const selectedTab = configState.selectedTab;
const tabs = [
CONFIGURATION_EDITOR_TAB.PROJECT_STRUCTURE,
CONFIGURATION_EDITOR_TAB.PROJECT_DEPENDENCIES,
];
const changeTab = (tab) => () => configState.setSelectedTab(tab);
let addButtonTitle = '';
switch (selectedTab) {
case CONFIGURATION_EDITOR_TAB.PROJECT_DEPENDENCIES:
addButtonTitle = 'Add project dependencies';
break;
default:
break;
}
const currentProjectConfiguration = configState.currentProjectConfiguration;
const deleteProjectDependency = (val) => () => currentProjectConfiguration.deleteProjectDependency(val);
const addValue = () => {
if (!isReadOnly) {
if (selectedTab === CONFIGURATION_EDITOR_TAB.PROJECT_DEPENDENCIES) {
const currentProjects = Array.from(configState.projects.values());
if (currentProjects.length) {
const projectToAdd = currentProjects[0];
const dependencyToAdd = new ProjectDependency(projectToAdd.coordinates);
dependencyToAdd.setVersionId(projectToAdd.latestVersion);
currentProjectConfiguration.addProjectDependency(dependencyToAdd);
}
else {
currentProjectConfiguration.addProjectDependency(new ProjectDependency(''));
}
}
}
};
const disableAddButton = selectedTab === CONFIGURATION_EDITOR_TAB.PROJECT_STRUCTURE || isReadOnly;
const updateConfigs = () => {
if (editorStore.hasUnpushedChanges) {
editorStore.setActionAlertInfo({
message: 'You have unpushed changes',
prompt: 'This action will discard these changes and refresh the application',
type: ActionAlertType.CAUTION,
onEnter: () => editorStore.setBlockGlobalHotkeys(true),
onClose: () => editorStore.setBlockGlobalHotkeys(false),
actions: [
{
label: 'Proceed to update project dependencies',
type: ActionAlertActionType.PROCEED_WITH_CAUTION,
handler: () => {
editorStore.setIgnoreNavigationBlocking(true);
flowResult(configState.updateConfigs()).catch(applicationStore.alertUnhandledError);
},
},
{
label: 'Abort',
type: ActionAlertActionType.PROCEED,
default: true,
},
],
});
}
else {
flowResult(configState.updateConfigs()).catch(applicationStore.alertUnhandledError);
}
};
useEffect(() => {
if (configState.projectConfiguration &&
selectedTab === CONFIGURATION_EDITOR_TAB.PROJECT_DEPENDENCIES &&
!configState.associatedProjectsAndVersionsFetched) {
flowResult(configState.fectchAssociatedProjectsAndVersions()).catch(applicationStore.alertUnhandledError);
}
}, [applicationStore, configState, selectedTab]);
if (!configState.projectConfiguration) {
return null;
}
return (_jsx("div", { className: "project-configuration-editor", children: _jsxs("div", { className: "panel", children: [_jsxs("div", { className: "panel__header", children: [_jsxs("div", { className: "panel__header__title", children: [_jsx("div", { className: "panel__header__title__label", children: "project configuration" }), _jsx("div", { className: "panel__header__title__content", children: sdlcState.currentProject?.name ?? '(unknown)' })] }), _jsx("button", {
// TODO: remove this ugly button when we integrate project configuration into change detection flow
className: "project-configuration-editor__update-btn", disabled: isReadOnly ||
configState.isUpdatingConfiguration ||
currentProjectConfiguration.hashCode ===
configState.originalConfig.hashCode, onClick: updateConfigs, tabIndex: -1, children: "Update" })] }), _jsxs("div", { className: "panel__header project-configuration-editor__tabs__header", children: [_jsx("div", { className: "project-configuration-editor__tabs", children: tabs.map((tab) => (_jsx("button", { onClick: changeTab(tab), className: clsx('project-configuration-editor__tab', {
'project-configuration-editor__tab--active': tab === selectedTab,
}), children: prettyCONSTName(tab) }, tab))) }), _jsx("div", { className: "panel__header__actions", children: _jsx("button", { className: "panel__header__action", disabled: disableAddButton, tabIndex: -1, onClick: addValue, title: addButtonTitle, children: _jsx(PlusIcon, {}) }) })] }), _jsxs("div", { className: "panel__content project-configuration-editor__content", children: [selectedTab === CONFIGURATION_EDITOR_TAB.PROJECT_STRUCTURE && (_jsx(ProjectStructureEditor, { projectConfig: currentProjectConfiguration, isReadOnly: isReadOnly })), selectedTab === CONFIGURATION_EDITOR_TAB.PROJECT_DEPENDENCIES && (_jsx("div", { className: "panel__content__lists", children: currentProjectConfiguration.projectDependencies.map((projectDependency) => (_jsx(ProjectDependencyEditor, { projectDependency: projectDependency, deleteValue: deleteProjectDependency(projectDependency), isReadOnly: isReadOnly }, projectDependency._UUID))) }))] })] }) }));
});
//# sourceMappingURL=ProjectConfigurationEditor.js.map