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

-