Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/management-system-v2/components/bpmn-canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ const BPMNCanvas = forwardRef<BPMNCanvasRef, BPMNCanvasProps>(
return () => resizeObserver.disconnect();
}, [resizeWithContainer]);

return <div className={className} style={{ height: '100%' }} ref={canvas}></div>;
return <div className={className} style={{ height: '100%', width: '100%' }} ref={canvas}></div>;
},
);

Expand Down
15 changes: 11 additions & 4 deletions src/management-system-v2/components/bpmn-viewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const BPMNViewer: FC<BPMNViewerProps> = ({
};

type LazyLoadingBPMNViewerProps = BPMNViewerProps & {
visible?: boolean;
fallback?: React.ReactNode;
};

Expand All @@ -68,15 +69,21 @@ export const LazyBPMNViewer: FC<LazyLoadingBPMNViewerProps> = ({
...props
}) => {
const ViewerContainerRef = useRef(null);
const visible = useLazyRendering(ViewerContainerRef);
const internalVisible = useLazyRendering(ViewerContainerRef);

const _visible = props.visible !== undefined ? props.visible : internalVisible;
const _props = { ...props, visible: undefined };

return (
<>
<div ref={ViewerContainerRef} style={{ height: '100%', width: '100%' }}>
{visible /* This ensures, that only elements, that are visible or close to beeing visible are rendered -> reduces requests for bpmn/xml */ ? (
<div
ref={ViewerContainerRef}
style={{ height: '100%', width: '100%', display: 'flex', justifyContent: 'center' }}
>
{_visible /* This ensures, that only elements, that are visible or close to beeing visible are rendered -> reduces requests for bpmn/xml */ ? (
<Suspense fallback={fallback}>
{/* Prevent sequential rendering/ get from showing the Icon-list */}
<BPMNViewer {...props} />
<BPMNViewer {..._props} />
</Suspense>
) : (
fallback
Expand Down
101 changes: 74 additions & 27 deletions src/management-system-v2/components/process-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
Skeleton,
Breadcrumb,
} from 'antd';
import { FolderOutlined } from '@ant-design/icons';
import { MdArrowBackIos, MdArrowForwardIos } from 'react-icons/md';
import { UserError } from '@/lib/user-error';
import { useAddControlCallback } from '@/lib/controls-store';
Expand All @@ -31,14 +32,15 @@ import dynamic from 'next/dynamic';

import '@toast-ui/editor/dist/toastui-editor.css';
import type { Editor as EditorClass } from '@toast-ui/react-editor';
import { isDummyFolderProcess } from '@/lib/process-export/export-preparation';
const TextEditor = dynamic(() => import('@/components/text-editor'), {
ssr: false,
loading: () => <Skeleton.Input size="large" />,
});

export type ProcessModalMode = 'create' | 'edit' | 'copy' | 'import';

type ProcessModalProps<T extends { name: string; description: string }> = {
type ProcessModalProps<T extends { id?: string; name: string; description: string }> = {
open: boolean;
title: string;
okText?: string;
Expand All @@ -52,6 +54,7 @@ type ProcessModalProps<T extends { name: string; description: string }> = {

const ProcessModal = <
T extends {
id?: string;
name: string;
description: string;
userDefinedId?: string;
Expand Down Expand Up @@ -214,6 +217,8 @@ const ProcessModal = <
{ level: 2, blocking: open, dependencies: [open] },
);

const [fullyOpen, setFullyOpen] = useState(false);

const renderFormContent = () => {
if (!initialData) {
return <ProcessInputs index={0} readonly={readonly} />;
Expand Down Expand Up @@ -255,13 +260,38 @@ const ProcessModal = <
>
{initialData.map((process, index) => (
<Card key={index}>
{process.bpmn && (
<>
<LazyBPMNViewer previewBpmn={process.bpmn} reduceLogo={true} fitOnResize />
<Divider style={{ width: '100%', marginLeft: '-20%' }} />
</>
)}
<ProcessInputsImport key={index} index={index} readonly={readonly} />
<>
{process.bpmn && (
<>
{isDummyFolderProcess(process) ? (
<div
style={{
height: '150px',
width: '100%',
display: 'flex',
justifyContent: 'center',
}}
>
<FolderOutlined style={{ fontSize: '100px' }} />
</div>
) : (
<LazyBPMNViewer
previewBpmn={process.bpmn}
reduceLogo={true}
fitOnResize
visible={fullyOpen}
/>
)}
<Divider style={{ width: '100%', marginLeft: '-20%' }} />
</>
)}
</>
<ProcessInputsImport
key={index}
index={index}
readonly={readonly}
isFolder={isDummyFolderProcess(process)}
/>
</Card>
))}
</Carousel>
Expand Down Expand Up @@ -309,6 +339,7 @@ const ProcessModal = <
flexDirection: 'column',
},
}}
afterOpenChange={(open) => setFullyOpen(open)}
>
<div style={{ overflowY: 'auto', flex: 1 }} className="Hide-Scroll-Bar">
{nameCollisions.length > 0 && showCollisions && (
Expand Down Expand Up @@ -395,6 +426,7 @@ type ProcessInputsProps = {
index: number;
initialName?: string;
readonly?: boolean;
isFolder?: boolean;
};

const ProcessInputs = ({ index, initialName, readonly = false }: ProcessInputsProps) => {
Expand Down Expand Up @@ -486,7 +518,7 @@ const ProcessInputs = ({ index, initialName, readonly = false }: ProcessInputsPr
);
};

const ProcessInputsImport = ({ index, readonly = false }: ProcessInputsProps) => {
const ProcessInputsImport = ({ index, readonly = false, isFolder }: ProcessInputsProps) => {
const instance = Form.useFormInstance();
const data = instance.getFieldsValue()[index];

Expand All @@ -497,6 +529,13 @@ const ProcessInputsImport = ({ index, readonly = false }: ProcessInputsProps) =>
<Form.Item hidden name={[index, 'folderPath']}>
<Input disabled />
</Form.Item>
{isFolder && (
<Alert
style={{ marginBottom: '10px' }}
type="warning"
title="This imports an empty folder without any processes."
/>
)}
{!!data?.folderPath && (
<Form.Item label="Import Path">
<Card size="small">
Expand All @@ -509,24 +548,32 @@ const ProcessInputsImport = ({ index, readonly = false }: ProcessInputsProps) =>
</Card>
</Form.Item>
)}
<ProcessInputs index={index} readonly={readonly} />
<Form.Item name={[index, 'creator']} label="Original Creator" rules={[{ required: false }]}>
<Input disabled />
</Form.Item>
<Form.Item
name={[index, 'creatorUsername']}
label="Original Creator Username"
rules={[{ required: false }]}
>
<Input disabled />
</Form.Item>
<Form.Item
name={[index, 'createdOn']}
label="Original Creation Date"
rules={[{ required: false }]}
>
<Input disabled />
</Form.Item>
{!isFolder && (
<>
<ProcessInputs index={index} readonly={readonly} />
<Form.Item
name={[index, 'creator']}
label="Original Creator"
rules={[{ required: false }]}
>
<Input disabled />
</Form.Item>
<Form.Item
name={[index, 'creatorUsername']}
label="Original Creator Username"
rules={[{ required: false }]}
>
<Input disabled />
</Form.Item>
<Form.Item
name={[index, 'createdOn']}
label="Original Creation Date"
rules={[{ required: false }]}
>
<Input disabled />
</Form.Item>
</>
)}
</>
);
};
Expand Down
11 changes: 11 additions & 0 deletions src/management-system-v2/lib/data/processes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
generateScriptTaskFileName,
generateStartFormFileName,
generateUserTaskFileName,
getDefinitionsId,
getDefinitionsVersionInformation,
getElementsByTagName,
setDefinitionsName,
Expand Down Expand Up @@ -66,6 +67,7 @@ import { getFolderById, getRootFolder } from './db/folders';
import { truthyFilter } from '../typescript-utils';
import { createFolder, getFolder, getFolderContents } from './folders';
import Ability from '../ability/abilityHelper';
import { isDummyFolderProcess } from '../process-export/export-preparation';

// Import necessary functions from processModule

Expand Down Expand Up @@ -275,6 +277,12 @@ export const addProcesses = async (
value.folderId = folder.id;
}

if (isDummyFolderProcess(value)) {
// if the process represents a placeholder for importing empty folders then skip adding the
// process after the folder structure was created
continue;
}

// bpmn prop gets deleted in addProcess()
const process = await _addProcess({ ...newProcess, folderId: value.folderId });

Expand Down Expand Up @@ -395,6 +403,9 @@ export const importProcesses = async (processData: ProcessData[], spaceId: strin
return importedProcesses;
}

// filter out dummy processes that were included in the import to generate empty folders
processData = processData.filter((p) => !isDummyFolderProcess(p));

for (let idx = 0; idx < importedProcesses.length; idx++) {
const process = importedProcesses[idx];
const artefacts = processData[idx].artefacts;
Expand Down
43 changes: 43 additions & 0 deletions src/management-system-v2/lib/process-export/export-preparation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import {
toBpmnXml,
getAllElements,
getStartFormFileNameMapping,
initXml,
setDefinitionsId,
setDefinitionsName,
} from '@proceed/bpmn-helper';

import { asyncMap, asyncFilter } from '../helpers/javascriptHelpers';
Expand Down Expand Up @@ -250,6 +253,30 @@ async function ensureProcessInfo(
isImport = false,
ability?: Ability,
) {
if (definitionId.startsWith(dummyProcessId)) {
let bpmn = initXml();
bpmn = (await setDefinitionsId(bpmn, definitionId)) as string;
bpmn = (await setDefinitionsName(bpmn, 'Placeholder Process To Keep The Folder')) as string;
exportData[definitionId] = {
definitionName: 'Placeholder Process To Keep The Folder',
folderPath,
isImport,
versions: {
latest: {
bpmn,
isImport,
layers: [],
imports: [],
},
},
scriptTasks: [],
userTasks: [],
images: [],
};

return;
}

if (!exportData[definitionId]) {
const process = await getProcess(definitionId, spaceId, undefined, ability);

Expand Down Expand Up @@ -295,6 +322,12 @@ async function ensureProcessInfo(
}
}

export const dummyProcessId = '___empty_dummy_process___';

export function isDummyFolderProcess(input: { id?: string }) {
return 'id' in input && input.id?.startsWith(dummyProcessId);
}

/**
* Gets the data that is needed to export all the requested processes with the given options
*
Expand All @@ -321,6 +354,16 @@ export async function prepareExport(
if (isUserErrorResponse(folder)) throw folder.error.message;
if (isUserErrorResponse(content)) throw content.error.message;

// make sure empty folders are exported by placing a dummy process into the folder
if (!content.length) {
return [
{
definitionId: `${dummyProcessId}_${path.split('/').join('_')}_${folder.name}`,
folderPath: path + '/' + folder.name,
},
];
}

return (
await asyncMap(content, async (entry) => {
if (entry.type !== 'folder') {
Expand Down
Loading