diff --git a/app/lib/file-context/processors/dmnProcessor.js b/app/lib/file-context/processors/dmnProcessor.js
index b1c9c7f468..155c5e8e42 100644
--- a/app/lib/file-context/processors/dmnProcessor.js
+++ b/app/lib/file-context/processors/dmnProcessor.js
@@ -13,6 +13,7 @@ const DmnModdle = require('dmn-moddle');
const moddle = new DmnModdle();
const {
+ findFileInParentDirectories,
is,
traverse
} = require('./util');
@@ -20,11 +21,14 @@ const {
module.exports = {
extensions: [ '.dmn' ],
process: async (item) => {
+ const processApplicationFilePath = findFileInParentDirectories(item.file.path, '.process-application');
+
const { rootElement } = await moddle.fromXML(item.file.contents);
return {
type: 'dmn',
- ids: findDecisionIds(rootElement)
+ ids: findDecisionIds(rootElement),
+ processApplication: processApplicationFilePath
};
}
};
diff --git a/app/lib/file-context/processors/formProcessor.js b/app/lib/file-context/processors/formProcessor.js
index 219ece980e..c1356e835a 100644
--- a/app/lib/file-context/processors/formProcessor.js
+++ b/app/lib/file-context/processors/formProcessor.js
@@ -8,14 +8,19 @@
* except in compliance with the MIT License.
*/
+const { findFileInParentDirectories } = require('./util');
+
module.exports = {
extensions: [ '.form' ],
process: async (item) => {
+ const processApplicationFilePath = findFileInParentDirectories(item.file.path, '.process-application');
+
const form = JSON.parse(item.file.contents);
return {
type: 'form',
- ids: [ form.id ]
+ ids: [ form.id ],
+ processApplication: processApplicationFilePath
};
}
};
\ No newline at end of file
diff --git a/app/lib/index.js b/app/lib/index.js
index e1128eb2c5..1eeb2202f0 100644
--- a/app/lib/index.js
+++ b/app/lib/index.js
@@ -219,6 +219,18 @@ renderer.on('system-clipboard:write-text', function(options, done) {
});
// file context //////////
+renderer.on('file-context:add-root', function(filePath, done) {
+ fileContext.addRoot(filePath);
+
+ done(null);
+});
+
+renderer.on('file-context:remove-root', function(filePath, done) {
+ fileContext.removeRoot(filePath);
+
+ done(null);
+});
+
renderer.on('file:opened', function(filePath, done) {
fileContext.fileOpened({ uri: toFileUrl(filePath) });
@@ -727,16 +739,18 @@ function bootstrap() {
const fileContext = new FileContext(fileContextLog);
- /**
- * @param { import('./file-context/types').IndexItem } item
- */
- function onIndexerUpdated(item) {
+ function onIndexerUpdated() {
fileContextLog.info('files', JSON.stringify(fileContext._indexer.getItems().map(({ file, metadata }) => ({ file: { ...file, contents: file.contents.substring(0, 10) + '...' }, metadata })), null, 2));
- renderer.send('file-context:changed', fileContext._indexer.getItems().map(({ file, metadata }) => ({ file, metadata })));
+
+ /* @type {import('./file-context/types').IndexItem} */
+ const items = fileContext._indexer.getItems();
+
+ renderer.send('file-context:changed', items.map(({ file, metadata }) => ({ file, metadata })));
}
fileContext.on('indexer:updated', onIndexerUpdated);
+ fileContext.on('indexer:removed', onIndexerUpdated);
app.on('quit', () => fileContext.close());
diff --git a/app/lib/menu/menu-builder.js b/app/lib/menu/menu-builder.js
index fac0a480a1..706b9da966 100644
--- a/app/lib/menu/menu-builder.js
+++ b/app/lib/menu/menu-builder.js
@@ -75,7 +75,6 @@ class MenuBuilder {
.appendSeparator()
.appendExportAs()
.appendCloseTab()
- .appendCloseProcessApplication()
.appendSeparator()
.appendQuit()
.get()
@@ -197,13 +196,6 @@ class MenuBuilder {
}
}));
- this.menu.append(new MenuItem({
- label: 'Open Process Application...',
- click: function() {
- app.emit('menu:action', 'open-process-application');
- }
- }));
-
this.appendOpenRecent();
return this;
@@ -335,18 +327,6 @@ class MenuBuilder {
return this;
}
- appendCloseProcessApplication() {
- this.menu.append(new MenuItem({
- label: 'Close Process Application',
- enabled: this.options.state.openProcessApplication,
- click: function() {
- app.emit('menu:action', 'close-process-application');
- }
- }));
-
- return this;
- }
-
appendSwitchTab(submenu) {
this.menu.append(new MenuItem({
label: 'Switch Tab...',
diff --git a/client/resources/icons/file-types/ProcessApplication.svg b/client/resources/icons/file-types/ProcessApplication.svg
new file mode 100644
index 0000000000..dfcdf23d81
--- /dev/null
+++ b/client/resources/icons/file-types/ProcessApplication.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/client/src/app/App.js b/client/src/app/App.js
index eca640f27e..66a552415e 100644
--- a/client/src/app/App.js
+++ b/client/src/app/App.js
@@ -75,6 +75,8 @@ import * as css from './App.less';
import Notifications, { NOTIFICATION_TYPES } from './notifications';
import { RecentTabs } from './RecentTabs';
+import ProcessApplicationIcon from '../../resources/icons/file-types/ProcessApplication.svg';
+
const log = debug('App');
export const EMPTY_TAB = {
@@ -1849,16 +1851,14 @@ export class App extends PureComponent {
}
const file = {
- name: 'new-process-application.process-application',
- contents: JSON.stringify({
- name: 'New Process Application'
- }, null, 2),
+ name: '.process-application',
+ contents: JSON.stringify({}, null, 2),
path: null
};
const fileSystem = this.getGlobal('fileSystem');
- const savedFile = await fileSystem.writeFile(`${directoryPath}/${file.name}`, file);
+ await fileSystem.writeFile(`${directoryPath}/${file.name}`, file);
this.processApplications.open(`${directoryPath}/${file.name}`);
}
@@ -2298,6 +2298,7 @@ export class App extends PureComponent {
await this.openFiles(files);
} }
+ tabsProvider={ this.props.tabsProvider }
/>
,
+ icon: ProcessApplicationIcon,
onClick: () => this.triggerAction('create-process-application')
}
];
@@ -2377,9 +2374,14 @@ export class App extends PureComponent {
} = this.props;
const {
+ file,
type
} = tab;
+ if (this.processApplications.hasOpen() && this.processApplications.getItem(file.path)) {
+ return ProcessApplicationIcon;
+ }
+
return tabsProvider.getTabIcon(type);
};
}
diff --git a/client/src/app/primitives/Tabbed.less b/client/src/app/primitives/Tabbed.less
index bb0aeab162..da90279b67 100644
--- a/client/src/app/primitives/Tabbed.less
+++ b/client/src/app/primitives/Tabbed.less
@@ -65,9 +65,19 @@
border-right: 1px solid var(--tab-border-right-color);
user-select: none;
- &.tab--process-application {
- background: linear-gradient(90deg, fuchsia 0%, transparent 75%);
- }
+ // &.tab--process-application {
+ // background: hsl(205, 100%, 45%) !important;
+ // color: white;
+
+ // .tab__close svg path {
+ // fill: white !important;
+ // }
+
+ // &.tab--active::after,
+ // &:not(.tab--active):hover::after {
+ // background: white !important;
+ // }
+ // }
.tab__content {
position: absolute;
@@ -133,7 +143,7 @@
width: 18px;
height: 18px;
border-radius: 50%;
- background-color: var(--tab-close-background-color);
+ // background-color: var(--tab-close-background-color);
.tab__icon-close {
margin: 1px 0px 1px -1px;
diff --git a/client/src/app/process-applications/ProcessApplications.js b/client/src/app/process-applications/ProcessApplications.js
index 649f5832d7..66cf5f0fd2 100644
--- a/client/src/app/process-applications/ProcessApplications.js
+++ b/client/src/app/process-applications/ProcessApplications.js
@@ -17,9 +17,17 @@ export default class ProcessApplications {
const activeTab = this._app.state.activeTab;
- if (activeTab && activeTab.file) {
+ if (this.hasOpen()) {
+ this._processApplicationItems = this._items.filter(item => item.metadata.processApplication === this._processApplication.file.path);
+
+ this._app.emit('process-applications:changed');
+ } else if (activeTab) {
const { file } = activeTab;
+ if (!file) {
+ return;
+ }
+
const item = this._items.find(item => item.file.path === file.path);
if (item && item.metadata.processApplication) {
@@ -31,6 +39,12 @@ export default class ProcessApplications {
this._app.on('app.activeTabChanged', ({ activeTab }) => {
const { file } = activeTab;
+ if (!file) {
+ this.close();
+
+ return;
+ }
+
const item = this._items.find(item => item.file.path === file.path);
if (!item || !item.metadata.processApplication) {
@@ -39,14 +53,13 @@ export default class ProcessApplications {
return;
}
- const { metadata } = item;
-
- if (metadata.processApplication) {
- this.open(metadata.processApplication);
+ if (item.metadata.processApplication) {
+ this.open(item.metadata.processApplication);
}
});
this._processApplication = null;
+ this._processApplicationItems = [];
this._items = [];
}
@@ -66,12 +79,14 @@ export default class ProcessApplications {
dirname
} = file;
- this._app.getGlobal('backend').send('file-context:add-root', dirname);
-
this._processApplication = {
file,
...JSON.parse(contents)
};
+
+ this._processApplicationItems = [];
+
+ this._app.getGlobal('backend').send('file-context:add-root', dirname);
} catch (err) {
console.error(err);
}
@@ -83,6 +98,7 @@ export default class ProcessApplications {
this._app.getGlobal('backend').send('file-context:remove-root', this._processApplication.file.dirname);
this._processApplication = null;
+ this._processApplicationItems = [];
this._app.emit('process-applications:changed');
}
@@ -96,12 +112,10 @@ export default class ProcessApplications {
}
getItems() {
- if (!this._processApplication) {
- return [];
- }
-
- const items = this._items.filter(({ metadata }) => metadata.processApplication === this._processApplication.file.path);
+ return this._processApplicationItems;
+ }
- return items;
+ getItem(path) {
+ return this._processApplicationItems.find(item => item.file.path === path);
}
}
\ No newline at end of file
diff --git a/client/src/app/process-applications/components/ProcessApplicationsStatusBar.js b/client/src/app/process-applications/components/ProcessApplicationsStatusBar.js
index 64f8e255f8..a93ce3e063 100644
--- a/client/src/app/process-applications/components/ProcessApplicationsStatusBar.js
+++ b/client/src/app/process-applications/components/ProcessApplicationsStatusBar.js
@@ -10,10 +10,14 @@
import React, { useEffect, useRef, useState } from 'react';
+import classnames from 'classnames';
+
import { Fill } from '../../slot-fill';
import { Overlay, Section } from '../../../shared/ui';
+import ProcessApplicationIcon from '../../../../resources/icons/file-types/ProcessApplication.svg';
+
import * as css from './ProcessApplicationsStatusBar.less';
export default function ProcessApplicationsStatusBar(props) {
@@ -23,7 +27,8 @@ export default function ProcessApplicationsStatusBar(props) {
const {
onOpen,
- processApplication
+ processApplication,
+ tabsProvider
} = props;
useEffect(() => {
@@ -40,8 +45,8 @@ export default function ProcessApplicationsStatusBar(props) {
return <>
-
{
@@ -53,41 +58,18 @@ export default function ProcessApplicationsStatusBar(props) {
{
items.filter(item => item.metadata.type === 'bpmn').length > 0 && <>
- BPMN
-
+
{
- items.filter(item => item.metadata.type === 'bpmn').map(item => {
- const { file } = item;
+ sortByType(items).map(item => {
+ const provider = tabsProvider.getProvider(item.metadata.type);
- return - onOpen(file.path) } key={ file.path } title={ file.path }>{ file.name }
;
- })
- }
-
- >
- }
- {
- items.filter(item => item.metadata.type === 'dmn').length > 0 && <>
- DMN
-
- {
- items.filter(item => item.metadata.type === 'dmn').map(item => {
- const { file } = item;
+ const Icon = provider.getIcon(item.file);
- return - onOpen(file.path) } key={ file.path } title={ file.path }>{ file.name }
;
- })
- }
-
- >
- }
- {
- items.filter(item => item.metadata.type === 'form').length > 0 && <>
- Form
-
- {
- items.filter(item => item.metadata.type === 'form').map(item => {
const { file } = item;
- return - onOpen(file.path) } key={ file.path } title={ file.path }>{ file.name }
;
+ return - onOpen(file.path) } key={ file.path } title={ file.path }>
+ { file.name }
+
;
})
}
@@ -99,3 +81,23 @@ export default function ProcessApplicationsStatusBar(props) {
}
>;
}
+
+function sortByType(items) {
+ const groupedByType = items.reduce((acc, item) => {
+ const { type } = item.metadata;
+
+ if (!acc[type]) {
+ acc[type] = [];
+ }
+
+ acc[type].push(item);
+
+ return acc;
+ }, {});
+
+ for (const type in groupedByType) {
+ groupedByType[type].sort((a, b) => a.file.name.localeCompare(b.file.name));
+ }
+
+ return Object.values(groupedByType).flat();
+}
\ No newline at end of file
diff --git a/client/src/app/process-applications/components/ProcessApplicationsStatusBar.less b/client/src/app/process-applications/components/ProcessApplicationsStatusBar.less
index 297e2a73e4..65e5eaa9d9 100644
--- a/client/src/app/process-applications/components/ProcessApplicationsStatusBar.less
+++ b/client/src/app/process-applications/components/ProcessApplicationsStatusBar.less
@@ -1,18 +1,29 @@
:local(.ProcessApplicationsButton) {
- background: linear-gradient(90deg, fuchsia 0%, transparent 100%) !important;
+ background: hsl(205, 100%, 45%) !important;
+
+ svg {
+ fill: white;
+ }
}
:local(.ProcessApplicationsOverlay) {
+ width: min-content;
+
.link {
cursor: pointer;
text-decoration: underline;
}
- .section {
- height: 500px !important;
+ ul {
+ padding: 0;
}
- ul.dashed {
- max-height: none !important;
+ li {
+ display: flex;
+ align-items: center;
+
+ svg {
+ margin-right: 6px;
+ }
}
}