@processmaker/modeler 1.43.0 → 1.43.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modeler.common.js +1213 -327
- package/dist/modeler.common.js.map +1 -1
- package/dist/modeler.umd.js +1213 -327
- package/dist/modeler.umd.js.map +1 -1
- package/dist/modeler.umd.min.js +4 -4
- package/dist/modeler.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/colorUtil.js +78 -0
- package/src/components/aiMessages/AiGenerateButton.vue +77 -0
- package/src/components/aiMessages/AssetsCreatedCard.vue +82 -0
- package/src/components/aiMessages/CreateAssetsCard.vue +92 -0
- package/src/components/aiMessages/CreateAssetsFailCard.vue +27 -0
- package/src/components/aiMessages/GeneratingAssetsCard.vue +77 -0
- package/src/components/modeler/Modeler.vue +190 -3
- package/src/components/multiplayer/remoteCursor/RemoteCursor.vue +14 -21
- package/src/components/railBottom/RailBottom.vue +4 -4
- package/src/components/topRail/TopRail.vue +4 -0
- package/src/components/topRail/multiplayerViewUsers/MultiplayerViewUsers.vue +1 -8
- package/src/components/topRail/multiplayerViewUsers/avatar/Avatar.vue +2 -76
- package/src/components/topRail/multiplayerViewUsers/avatar/avatar.scss +0 -1
- package/src/components/welcome/WelcomeMessage.vue +1 -6
- package/src/multiplayer/multiplayer.js +58 -16
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
@close="close"
|
|
24
24
|
@save-state="pushToUndoStack"
|
|
25
25
|
@clearSelection="clearSelection"
|
|
26
|
-
:players="
|
|
26
|
+
:players="filteredPlayers"
|
|
27
27
|
@action="handleToolbarAction"
|
|
28
28
|
/>
|
|
29
29
|
<b-row class="modeler h-100">
|
|
@@ -56,6 +56,29 @@
|
|
|
56
56
|
v-if="showWelcomeMessage"
|
|
57
57
|
/>
|
|
58
58
|
|
|
59
|
+
<CreateAssetsCard
|
|
60
|
+
ref="createAssetsCard"
|
|
61
|
+
v-if="isAiGenerated"
|
|
62
|
+
@onGenerateAssets="generateAssets()"
|
|
63
|
+
@closeCreateAssets="onCloseCreateAssets()"
|
|
64
|
+
/>
|
|
65
|
+
|
|
66
|
+
<GeneratingAssetsCard
|
|
67
|
+
ref="generatingAssetsCard"
|
|
68
|
+
v-if="generatingAi"
|
|
69
|
+
/>
|
|
70
|
+
|
|
71
|
+
<AssetsCreatedCard
|
|
72
|
+
ref="assetsCreatedCard"
|
|
73
|
+
v-if="assetsCreated"
|
|
74
|
+
@closeAssetsCreated="onCloseAssetsCreated()"
|
|
75
|
+
/>
|
|
76
|
+
|
|
77
|
+
<CreateAssetsFailCard
|
|
78
|
+
ref="createAssetsFailCard"
|
|
79
|
+
v-if="false"
|
|
80
|
+
/>
|
|
81
|
+
|
|
59
82
|
<InspectorButton
|
|
60
83
|
ref="inspector-button"
|
|
61
84
|
v-show="showComponent && showInspectorButton"
|
|
@@ -143,6 +166,7 @@
|
|
|
143
166
|
/>
|
|
144
167
|
|
|
145
168
|
<RailBottom
|
|
169
|
+
v-if="!generatingAi"
|
|
146
170
|
:nodeTypes="nodeTypes"
|
|
147
171
|
:paper-manager="paperManager"
|
|
148
172
|
:graph="graph"
|
|
@@ -165,6 +189,11 @@
|
|
|
165
189
|
@save-state="pushToUndoStack"
|
|
166
190
|
:isMultiplayer="isMultiplayer"
|
|
167
191
|
/>
|
|
192
|
+
<RemoteCursor
|
|
193
|
+
v-for="player in filteredPlayers"
|
|
194
|
+
:key="player.id"
|
|
195
|
+
:data="player"
|
|
196
|
+
/>
|
|
168
197
|
</b-row>
|
|
169
198
|
</span>
|
|
170
199
|
</template>
|
|
@@ -172,12 +201,17 @@
|
|
|
172
201
|
<script>
|
|
173
202
|
|
|
174
203
|
import Vue from 'vue';
|
|
204
|
+
|
|
175
205
|
import _ from 'lodash';
|
|
176
206
|
import { dia } from 'jointjs';
|
|
177
207
|
import boundaryEventConfig from '../nodes/boundaryEvent';
|
|
178
208
|
import BpmnModdle from 'bpmn-moddle';
|
|
179
209
|
import ExplorerRail from '../rails/explorer-rail/explorer';
|
|
180
210
|
import WelcomeMessage from '../welcome/WelcomeMessage.vue';
|
|
211
|
+
import CreateAssetsCard from '../aiMessages/CreateAssetsCard.vue';
|
|
212
|
+
import GeneratingAssetsCard from '../aiMessages/GeneratingAssetsCard.vue';
|
|
213
|
+
import AssetsCreatedCard from '../aiMessages/AssetsCreatedCard.vue';
|
|
214
|
+
import CreateAssetsFailCard from '../aiMessages/CreateAssetsFailCard.vue';
|
|
181
215
|
import { isJSON } from 'lodash-contrib';
|
|
182
216
|
import pull from 'lodash/pull';
|
|
183
217
|
import remove from 'lodash/remove';
|
|
@@ -251,6 +285,10 @@ export default {
|
|
|
251
285
|
Selection,
|
|
252
286
|
RailBottom,
|
|
253
287
|
WelcomeMessage,
|
|
288
|
+
CreateAssetsCard,
|
|
289
|
+
GeneratingAssetsCard,
|
|
290
|
+
AssetsCreatedCard,
|
|
291
|
+
CreateAssetsFailCard,
|
|
254
292
|
RemoteCursor,
|
|
255
293
|
},
|
|
256
294
|
props: {
|
|
@@ -348,6 +386,12 @@ export default {
|
|
|
348
386
|
isResizingPreview: false,
|
|
349
387
|
currentCursorPosition: 0,
|
|
350
388
|
previewPanelWidth: 600,
|
|
389
|
+
isAiGenerated: window.ProcessMaker?.modeler?.isAiGenerated,
|
|
390
|
+
generatingAi: false,
|
|
391
|
+
assetsCreated: false,
|
|
392
|
+
// ^ TODO: To be changed depending on microservice response
|
|
393
|
+
currentNonce: null,
|
|
394
|
+
promptSessionId: '',
|
|
351
395
|
flowTypes: [
|
|
352
396
|
'processmaker-modeler-sequence-flow',
|
|
353
397
|
'processmaker-modeler-message-flow',
|
|
@@ -401,6 +445,12 @@ export default {
|
|
|
401
445
|
},
|
|
402
446
|
},
|
|
403
447
|
computed: {
|
|
448
|
+
filteredPlayers() {
|
|
449
|
+
const allPlayers = _.uniqBy(this.players, 'name');
|
|
450
|
+
return allPlayers.filter(player => {
|
|
451
|
+
return player.name.toLowerCase() !== window.ProcessMaker.user?.fullName.toLowerCase();
|
|
452
|
+
});
|
|
453
|
+
},
|
|
404
454
|
showWelcomeMessage() {
|
|
405
455
|
return !this.selectedNode && !this.nodes.length && !store.getters.isReadOnly && this.isLoaded;
|
|
406
456
|
},
|
|
@@ -1613,6 +1663,7 @@ export default {
|
|
|
1613
1663
|
},
|
|
1614
1664
|
pointerMoveHandler(event) {
|
|
1615
1665
|
const { clientX: x, clientY: y } = event;
|
|
1666
|
+
window.ProcessMaker.EventBus.$emit('multiplayer-updateMousePosition', { top: y, left: x });
|
|
1616
1667
|
if (store.getters.isReadOnly) {
|
|
1617
1668
|
if (this.canvasDragPosition && !this.clientLeftPaper) {
|
|
1618
1669
|
this.paperManager.translate(
|
|
@@ -1662,8 +1713,23 @@ export default {
|
|
|
1662
1713
|
enableMultiplayer(value) {
|
|
1663
1714
|
store.commit('enableMultiplayer', value);
|
|
1664
1715
|
},
|
|
1665
|
-
|
|
1666
|
-
this.players
|
|
1716
|
+
emptyPlayers(){
|
|
1717
|
+
this.players = [];
|
|
1718
|
+
},
|
|
1719
|
+
addPlayer(data) {
|
|
1720
|
+
const player = this.players.find(player => player.id === data.id);
|
|
1721
|
+
if (!player) {
|
|
1722
|
+
this.players.push(data);
|
|
1723
|
+
}
|
|
1724
|
+
},
|
|
1725
|
+
/**
|
|
1726
|
+
* Update Client Cursor
|
|
1727
|
+
* @param {Object} data
|
|
1728
|
+
*/
|
|
1729
|
+
updateClientCursor(data) {
|
|
1730
|
+
if (data) {
|
|
1731
|
+
this.players = this.players.map((item) => (item.id === data.id ? { ...item, ...data } : item));
|
|
1732
|
+
}
|
|
1667
1733
|
},
|
|
1668
1734
|
removePlayer(playerId) {
|
|
1669
1735
|
const playerIndex = this.players.findIndex(player => player.id === playerId);
|
|
@@ -1678,6 +1744,119 @@ export default {
|
|
|
1678
1744
|
updateLasso(){
|
|
1679
1745
|
this.$refs.selector.updateSelectionBox();
|
|
1680
1746
|
},
|
|
1747
|
+
getNonce() {
|
|
1748
|
+
const max = 999999999999999;
|
|
1749
|
+
const nonce = Math.floor(Math.random() * max);
|
|
1750
|
+
this.currentNonce = nonce;
|
|
1751
|
+
localStorage.currentNonce = this.currentNonce;
|
|
1752
|
+
},
|
|
1753
|
+
getPromptSessionForUser() {
|
|
1754
|
+
// Get sessions list
|
|
1755
|
+
let promptSessions = localStorage.getItem('promptSessions');
|
|
1756
|
+
|
|
1757
|
+
// If promptSessions does not exist, set it as an empty array
|
|
1758
|
+
promptSessions = promptSessions ? JSON.parse(promptSessions) : [];
|
|
1759
|
+
let item = promptSessions.find(item => item.userId === window.ProcessMaker?.modeler?.process?.user_id && item.server === window.location.host);
|
|
1760
|
+
|
|
1761
|
+
if (item) {
|
|
1762
|
+
return item.promptSessionId;
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
return '';
|
|
1766
|
+
},
|
|
1767
|
+
setPromptSessions(promptSessionId) {
|
|
1768
|
+
let index = 'userId';
|
|
1769
|
+
let id = window.ProcessMaker?.modeler?.process?.user_id;
|
|
1770
|
+
|
|
1771
|
+
// Get sessions list
|
|
1772
|
+
let promptSessions = localStorage.getItem('promptSessions');
|
|
1773
|
+
|
|
1774
|
+
// If promptSessions does not exist, set it as an empty array
|
|
1775
|
+
promptSessions = promptSessions ? JSON.parse(promptSessions) : [];
|
|
1776
|
+
|
|
1777
|
+
let item = promptSessions.find(item => item[index] === id && item.server === window.location.host);
|
|
1778
|
+
|
|
1779
|
+
if (item) {
|
|
1780
|
+
item.promptSessionId = promptSessionId;
|
|
1781
|
+
} else {
|
|
1782
|
+
promptSessions.push({ [index]: id, server: window.location.host, promptSessionId });
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
localStorage.setItem('promptSessions', JSON.stringify(promptSessions));
|
|
1786
|
+
},
|
|
1787
|
+
removePromptSessionForUser() {
|
|
1788
|
+
// Get sessions list
|
|
1789
|
+
let promptSessions = localStorage.getItem('promptSessions');
|
|
1790
|
+
|
|
1791
|
+
// If promptSessions does not exist, set it as an empty array
|
|
1792
|
+
promptSessions = promptSessions ? JSON.parse(promptSessions) : [];
|
|
1793
|
+
|
|
1794
|
+
let item = promptSessions.find(item => item.userId === window.ProcessMaker?.modeler?.process?.user_id && item.server === window.location.host);
|
|
1795
|
+
|
|
1796
|
+
if (item) {
|
|
1797
|
+
item.promptSessionId = '';
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
localStorage.setItem('promptSessions', JSON.stringify(promptSessions));
|
|
1801
|
+
},
|
|
1802
|
+
fetchHistory() {
|
|
1803
|
+
let url = '/package-ai/getPromptSessionHistory';
|
|
1804
|
+
|
|
1805
|
+
let params = {
|
|
1806
|
+
server: window.location.host,
|
|
1807
|
+
processId: this.processId,
|
|
1808
|
+
};
|
|
1809
|
+
|
|
1810
|
+
if (this.promptSessionId && this.promptSessionId !== null && this.promptSessionId !== '') {
|
|
1811
|
+
params = {
|
|
1812
|
+
promptSessionId: this.promptSessionId,
|
|
1813
|
+
};
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
window.ProcessMaker.apiClient.post(url, params)
|
|
1817
|
+
.then(response => {
|
|
1818
|
+
this.setPromptSessions((response.data.promptSessionId));
|
|
1819
|
+
this.promptSessionId = (response.data.promptSessionId);
|
|
1820
|
+
localStorage.promptSessionId = (response.data.promptSessionId);
|
|
1821
|
+
}).catch((error) => {
|
|
1822
|
+
const errorMsg = error.response?.data?.message || error.message;
|
|
1823
|
+
|
|
1824
|
+
if (error.response.status === 404) {
|
|
1825
|
+
this.removePromptSessionForUser();
|
|
1826
|
+
localStorage.promptSessionId = '';
|
|
1827
|
+
this.promptSessionId = '';
|
|
1828
|
+
} else {
|
|
1829
|
+
window.ProcessMaker.alert(errorMsg, 'danger');
|
|
1830
|
+
}
|
|
1831
|
+
});
|
|
1832
|
+
},
|
|
1833
|
+
generateAssets() {
|
|
1834
|
+
this.getNonce();
|
|
1835
|
+
|
|
1836
|
+
// TODO: Add endpoint to get the promprSessionId
|
|
1837
|
+
|
|
1838
|
+
const params = {
|
|
1839
|
+
promptSessionId: this.promptSessionId,
|
|
1840
|
+
nonce: this.currentNonce,
|
|
1841
|
+
processId: window.ProcessMaker?.modeler?.process?.id,
|
|
1842
|
+
};
|
|
1843
|
+
|
|
1844
|
+
const url = '/package-ai/generateProcessArtifacts';
|
|
1845
|
+
|
|
1846
|
+
window.ProcessMaker.apiClient.post(url, params)
|
|
1847
|
+
.then(() => {
|
|
1848
|
+
})
|
|
1849
|
+
.catch((error) => {
|
|
1850
|
+
const errorMsg = error.response?.data?.message || error.message;
|
|
1851
|
+
window.ProcessMaker.alert(errorMsg, 'danger');
|
|
1852
|
+
});
|
|
1853
|
+
},
|
|
1854
|
+
onCloseCreateAssets() {
|
|
1855
|
+
this.isAiGenerated = false;
|
|
1856
|
+
},
|
|
1857
|
+
onCloseAssetsCreated() {
|
|
1858
|
+
this.assetsCreated = false;
|
|
1859
|
+
},
|
|
1681
1860
|
},
|
|
1682
1861
|
created() {
|
|
1683
1862
|
if (runningInCypressTest()) {
|
|
@@ -1866,6 +2045,14 @@ export default {
|
|
|
1866
2045
|
this.redirect(redirectUrl);
|
|
1867
2046
|
}
|
|
1868
2047
|
});
|
|
2048
|
+
|
|
2049
|
+
// AI Setup
|
|
2050
|
+
this.currentNonce = localStorage.currentNonce;
|
|
2051
|
+
if (!localStorage.getItem('promptSessions') || localStorage.getItem('promptSessions') === 'null') {
|
|
2052
|
+
localStorage.setItem('promptSessions', JSON.stringify([]));
|
|
2053
|
+
}
|
|
2054
|
+
this.promptSessionId = this.getPromptSessionForUser();
|
|
2055
|
+
this.fetchHistory();
|
|
1869
2056
|
},
|
|
1870
2057
|
};
|
|
1871
2058
|
</script>
|
|
@@ -1,33 +1,19 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="remote-cursor" :style="{ left: left + 'px', top: top + 'px' }">
|
|
3
|
-
<
|
|
4
|
-
|
|
2
|
+
<div class="remote-cursor" :style="{ left: data.cursor.left + 'px', top: data.cursor.top + 'px' }">
|
|
3
|
+
<svg width="23" height="19" viewBox="0 0 23 19" xmlns="http://www.w3.org/2000/svg">
|
|
4
|
+
<path d="M11.5 17.5L2 1L20.5 7L13 9L11.5 17.5Z" :stroke="stroke" :fill="data.color"/>
|
|
5
|
+
</svg>
|
|
5
6
|
<div class="remote-username">
|
|
6
|
-
{{
|
|
7
|
+
{{ data.name }}
|
|
7
8
|
</div>
|
|
8
9
|
</div>
|
|
9
10
|
</template>
|
|
10
11
|
|
|
11
12
|
<script>
|
|
12
|
-
import InlineSvg from 'vue-inline-svg';
|
|
13
|
-
|
|
14
13
|
export default {
|
|
15
|
-
components: {
|
|
16
|
-
InlineSvg,
|
|
17
|
-
},
|
|
18
14
|
props: {
|
|
19
|
-
|
|
20
|
-
type:
|
|
21
|
-
default: '#000000',
|
|
22
|
-
},
|
|
23
|
-
username: {
|
|
24
|
-
type: String,
|
|
25
|
-
},
|
|
26
|
-
top: {
|
|
27
|
-
type: Number,
|
|
28
|
-
},
|
|
29
|
-
left: {
|
|
30
|
-
type: Number,
|
|
15
|
+
data: {
|
|
16
|
+
type: Object,
|
|
31
17
|
},
|
|
32
18
|
},
|
|
33
19
|
data() {
|
|
@@ -35,6 +21,12 @@ export default {
|
|
|
35
21
|
cursorIcon: require('@/components/multiplayer/remoteCursor/cursor.svg'),
|
|
36
22
|
};
|
|
37
23
|
},
|
|
24
|
+
computed: {
|
|
25
|
+
stroke: () => {
|
|
26
|
+
return '#212529';
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
|
|
38
30
|
};
|
|
39
31
|
</script>
|
|
40
32
|
|
|
@@ -45,6 +37,7 @@ export default {
|
|
|
45
37
|
display: flex;
|
|
46
38
|
width: auto;
|
|
47
39
|
height: 34px;
|
|
40
|
+
z-index: 2;
|
|
48
41
|
}
|
|
49
42
|
|
|
50
43
|
&-username {
|
|
@@ -84,12 +84,12 @@ export default {
|
|
|
84
84
|
// Control coordinates
|
|
85
85
|
const controlEl = entries[0].target.getBoundingClientRect();
|
|
86
86
|
// Zoom coordinates
|
|
87
|
-
const zoomEl = this.$refs.zoomBox
|
|
87
|
+
const zoomEl = this.$refs.zoomBox?.$el.getBoundingClientRect();
|
|
88
88
|
// Undo/Redo coordinates
|
|
89
|
-
const undoRedoEl = this.$refs.undoRedoBox
|
|
89
|
+
const undoRedoEl = this.$refs.undoRedoBox?.$el.getBoundingClientRect();
|
|
90
90
|
|
|
91
91
|
// Checks overlapping
|
|
92
|
-
if (this.overlap) {
|
|
92
|
+
if (this.overlap && undoRedoEl) {
|
|
93
93
|
if (controlEl.width < this.widthOverlapControl) {
|
|
94
94
|
// Get the computed styles of the ZoomControl
|
|
95
95
|
const zoomStyles = window.getComputedStyle(this.$refs.zoomBox.$el);
|
|
@@ -107,7 +107,7 @@ export default {
|
|
|
107
107
|
this.overlap = false;
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
|
-
} else if (undoRedoEl
|
|
110
|
+
} else if (undoRedoEl?.left < zoomEl?.right) {
|
|
111
111
|
this.overlap = true;
|
|
112
112
|
this.widthOverlapControl = controlEl.width;
|
|
113
113
|
this.leftOverlapUndoRedo = undoRedoEl.left;
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
@openPanel="handleOpenPanel"
|
|
8
8
|
/>
|
|
9
9
|
|
|
10
|
+
<AiGenerateButton/>
|
|
11
|
+
|
|
10
12
|
<ValidateButton @openIssue="handleOpenIssue" />
|
|
11
13
|
|
|
12
14
|
<ValidatePanel
|
|
@@ -22,11 +24,13 @@
|
|
|
22
24
|
import store from '@/store';
|
|
23
25
|
import { ValidateButton, ValidateIssue, ValidatePanel } from '@/components/topRail/validateControl';
|
|
24
26
|
import MultiplayerViewUsers from '@/components/topRail/multiplayerViewUsers/MultiplayerViewUsers';
|
|
27
|
+
import AiGenerateButton from '../aiMessages/AiGenerateButton.vue';
|
|
25
28
|
export default {
|
|
26
29
|
components: {
|
|
27
30
|
ValidateButton,
|
|
28
31
|
ValidateIssue,
|
|
29
32
|
ValidatePanel,
|
|
33
|
+
AiGenerateButton,
|
|
30
34
|
MultiplayerViewUsers,
|
|
31
35
|
},
|
|
32
36
|
props: {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<b-avatar-group class="container" v-show="isMultiplayer">
|
|
3
|
-
<template v-for="item in
|
|
3
|
+
<template v-for="item in players" >
|
|
4
4
|
<Avatar
|
|
5
5
|
:badgeBackgroundColor="item.color"
|
|
6
6
|
:imgSrc="item.avatar"
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
</template>
|
|
14
14
|
|
|
15
15
|
<script>
|
|
16
|
-
import { uniqBy } from 'lodash';
|
|
17
16
|
import Avatar from '@/components/topRail/multiplayerViewUsers/avatar/Avatar';
|
|
18
17
|
import store from '@/store';
|
|
19
18
|
|
|
@@ -28,12 +27,6 @@ export default {
|
|
|
28
27
|
},
|
|
29
28
|
},
|
|
30
29
|
computed: {
|
|
31
|
-
filteredPlayers() {
|
|
32
|
-
const allPlayers = uniqBy(this.players, 'name');
|
|
33
|
-
return allPlayers.filter(player => {
|
|
34
|
-
return player.name.toLowerCase() !== window.ProcessMaker.user?.fullName.toLowerCase();
|
|
35
|
-
});
|
|
36
|
-
},
|
|
37
30
|
isMultiplayer: () => store.getters.isMultiplayer,
|
|
38
31
|
},
|
|
39
32
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<span
|
|
3
3
|
class="b-avatar rounded-circle"
|
|
4
|
-
:style="{'backgroundColor':
|
|
4
|
+
:style="{'backgroundColor': backgroundColor}"
|
|
5
5
|
>
|
|
6
6
|
<span v-if="imgSrc" class="b-avatar-img" :id="id">
|
|
7
7
|
<img :src="imgSrc" :alt="userName">
|
|
@@ -46,16 +46,9 @@ export default {
|
|
|
46
46
|
saturation: 50,
|
|
47
47
|
lightness: 50,
|
|
48
48
|
range: 10,
|
|
49
|
+
backgroundColor: '#104A75',
|
|
49
50
|
};
|
|
50
51
|
},
|
|
51
|
-
computed: {
|
|
52
|
-
saturationRange() {
|
|
53
|
-
return this.getRange(this.saturation, this.range);
|
|
54
|
-
},
|
|
55
|
-
lightnessRange() {
|
|
56
|
-
return this.getRange(this.lightness, this.range);
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
52
|
methods: {
|
|
60
53
|
/**
|
|
61
54
|
* Get the initials from a given name.
|
|
@@ -69,73 +62,6 @@ export default {
|
|
|
69
62
|
const lastNameIn = nameArray[nameArray.length - 1].charAt(0).toUpperCase();
|
|
70
63
|
return `${firstNameIn}${lastNameIn}`;
|
|
71
64
|
},
|
|
72
|
-
/**
|
|
73
|
-
* Calculates a hash value for a given string.
|
|
74
|
-
*
|
|
75
|
-
* @param {string} str - The input string for which the hash needs to be calculated.
|
|
76
|
-
* @returns {number} The calculated hash value for the input string.
|
|
77
|
-
*/
|
|
78
|
-
getHashOfString(str){
|
|
79
|
-
let hash = 0;
|
|
80
|
-
for (let i = 0; i < str.length; i++) {
|
|
81
|
-
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
|
82
|
-
}
|
|
83
|
-
hash = Math.abs(hash);
|
|
84
|
-
return hash;
|
|
85
|
-
},
|
|
86
|
-
/**
|
|
87
|
-
* Calculates a range around a given value.
|
|
88
|
-
*
|
|
89
|
-
* @param {number} value - The central value.
|
|
90
|
-
* @param {number} range - The range value.
|
|
91
|
-
* @returns {number[]} An array containing the lower and upper bounds of the range.
|
|
92
|
-
*/
|
|
93
|
-
getRange(value, range) {
|
|
94
|
-
return [Math.max(0, value-range), Math.min(value + range, 100)];
|
|
95
|
-
},
|
|
96
|
-
/**
|
|
97
|
-
* Get the hash number to within our range
|
|
98
|
-
*
|
|
99
|
-
* @param {Number} hash
|
|
100
|
-
* @param {Number} min
|
|
101
|
-
* @param {Number} max
|
|
102
|
-
* @returns {Number}
|
|
103
|
-
*/
|
|
104
|
-
normalizeHash(hash, min, max){
|
|
105
|
-
return Math.floor((hash % (max - min)) + min);
|
|
106
|
-
},
|
|
107
|
-
/**
|
|
108
|
-
*Generate Unique Color, create a string using our h,s,l values.
|
|
109
|
-
* @param {String} name
|
|
110
|
-
* @param {Array} saturationRange
|
|
111
|
-
* @param {Array} lightnessRange
|
|
112
|
-
* @returns {Number}
|
|
113
|
-
*/
|
|
114
|
-
generateHSL(name, saturationRange, lightnessRange) {
|
|
115
|
-
const hash = this.getHashOfString(name);
|
|
116
|
-
const h = this.normalizeHash(hash, 0, 360);
|
|
117
|
-
const s = this.normalizeHash(hash, saturationRange[0], saturationRange[1]);
|
|
118
|
-
const l = this.normalizeHash(hash, lightnessRange[0], lightnessRange[1]);
|
|
119
|
-
return [h, s, l];
|
|
120
|
-
},
|
|
121
|
-
/**
|
|
122
|
-
* Convert HSL array to string
|
|
123
|
-
* @param {Array} hsl
|
|
124
|
-
* @returns {String}
|
|
125
|
-
*/
|
|
126
|
-
HSLtoString(hsl) {
|
|
127
|
-
return `hsl(${hsl[0]}, ${hsl[1]}%, ${hsl[2]}%)`;
|
|
128
|
-
},
|
|
129
|
-
/**
|
|
130
|
-
* Generate a unique hsl value.
|
|
131
|
-
* @param {String} name
|
|
132
|
-
* @param {Array} saturationRange
|
|
133
|
-
* @param {Array} lightnessRange
|
|
134
|
-
* @returns {String}
|
|
135
|
-
*/
|
|
136
|
-
generateColorHsl(id, saturationRange, lightnessRange) {
|
|
137
|
-
return this.HSLtoString(this.generateHSL(id, saturationRange, lightnessRange));
|
|
138
|
-
},
|
|
139
65
|
},
|
|
140
66
|
};
|
|
141
67
|
|
|
@@ -148,7 +148,7 @@ export default {
|
|
|
148
148
|
},
|
|
149
149
|
};
|
|
150
150
|
</script>
|
|
151
|
-
<style>
|
|
151
|
+
<style scoped>
|
|
152
152
|
.message {
|
|
153
153
|
color: #5f666d;
|
|
154
154
|
font-style: italic;
|
|
@@ -187,11 +187,6 @@ export default {
|
|
|
187
187
|
border-color: #0872C2;
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
-
.ai-icon {
|
|
191
|
-
width: 22px;
|
|
192
|
-
height: 22px;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
190
|
.ai-icon {
|
|
196
191
|
width: 22px;
|
|
197
192
|
height: 22px;
|
|
@@ -6,7 +6,7 @@ import Room from './room';
|
|
|
6
6
|
import store from '@/store';
|
|
7
7
|
import { getBoundaryEventData } from '@/components/nodes/boundaryEvent/boundaryEventUtils';
|
|
8
8
|
import { InspectorUtils } from './inspector.utils';
|
|
9
|
-
|
|
9
|
+
import ColorUtil from '../colorUtil';
|
|
10
10
|
export default class Multiplayer {
|
|
11
11
|
clientIO = null;
|
|
12
12
|
yDoc = null;
|
|
@@ -16,7 +16,7 @@ export default class Multiplayer {
|
|
|
16
16
|
room = null;
|
|
17
17
|
inspector = null;
|
|
18
18
|
deletedItem = null;
|
|
19
|
-
|
|
19
|
+
colorUtil = null;
|
|
20
20
|
constructor(modeler) {
|
|
21
21
|
// define document
|
|
22
22
|
this.yDoc = new Y.Doc();
|
|
@@ -42,33 +42,28 @@ export default class Multiplayer {
|
|
|
42
42
|
} else {
|
|
43
43
|
this.clientIO.disconnect();
|
|
44
44
|
}
|
|
45
|
+
this.colorUtil = new ColorUtil(50, 50, 10);
|
|
45
46
|
}
|
|
47
|
+
|
|
46
48
|
webSocketEvents() {
|
|
47
49
|
this.clientIO.on('connect', () => {
|
|
48
50
|
// Join the room
|
|
51
|
+
this.modeler.emptyPlayers();
|
|
49
52
|
this.clientIO.emit('joinRoom', {
|
|
50
53
|
roomName: this.room.getRoom(),
|
|
51
54
|
clientName: window.ProcessMaker.user?.fullName,
|
|
52
55
|
clientAvatar: window.ProcessMaker.user?.avatar,
|
|
56
|
+
clientColor: window.ProcessMaker.user?.color || this.colorUtil.randomColor(window.ProcessMaker.user?.fullName),
|
|
57
|
+
clientCursor: {
|
|
58
|
+
top: 300,
|
|
59
|
+
left: 300,
|
|
60
|
+
},
|
|
53
61
|
});
|
|
54
62
|
});
|
|
55
63
|
|
|
56
64
|
this.clientIO.on('clientJoined', (payload) => {
|
|
57
65
|
this.modeler.enableMultiplayer(payload.isMultiplayer);
|
|
58
|
-
|
|
59
|
-
if (payload.isMultiplayer) {
|
|
60
|
-
payload.clients.map(client => {
|
|
61
|
-
const newPlayer = {
|
|
62
|
-
id: client.id,
|
|
63
|
-
name: client.name,
|
|
64
|
-
color: client.color,
|
|
65
|
-
avatar: client.avatar || null,
|
|
66
|
-
top: 90,
|
|
67
|
-
left: 80,
|
|
68
|
-
};
|
|
69
|
-
this.modeler.addPlayer(newPlayer);
|
|
70
|
-
});
|
|
71
|
-
}
|
|
66
|
+
this.addPlayers(payload);
|
|
72
67
|
});
|
|
73
68
|
|
|
74
69
|
this.clientIO.on('clientLeft', (payload) => {
|
|
@@ -85,6 +80,10 @@ export default class Multiplayer {
|
|
|
85
80
|
this.syncLocalNodes(clientId);
|
|
86
81
|
}
|
|
87
82
|
});
|
|
83
|
+
|
|
84
|
+
this.clientIO.on('updateUserCursor', async(payload) => {
|
|
85
|
+
this.updateClientCursor(payload);
|
|
86
|
+
});
|
|
88
87
|
|
|
89
88
|
// Listen for updates when a new element is added
|
|
90
89
|
this.clientIO.on('createElement', async(payload) => {
|
|
@@ -198,6 +197,49 @@ export default class Multiplayer {
|
|
|
198
197
|
this.updateFlows(data);
|
|
199
198
|
}
|
|
200
199
|
});
|
|
200
|
+
window.ProcessMaker.EventBus.$on('multiplayer-updateMousePosition', ( data ) => {
|
|
201
|
+
if (this.modeler.isMultiplayer) {
|
|
202
|
+
this.updateMousePosition(data);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Add a Player
|
|
208
|
+
* @param {Object} payload
|
|
209
|
+
*/
|
|
210
|
+
addPlayers(payload) {
|
|
211
|
+
if (payload.isMultiplayer) {
|
|
212
|
+
payload.clients.map(client => {
|
|
213
|
+
const newPlayer = {
|
|
214
|
+
id: client.id,
|
|
215
|
+
name: client.name,
|
|
216
|
+
color: client.color,
|
|
217
|
+
avatar: client.avatar,
|
|
218
|
+
cursor: client.cursor,
|
|
219
|
+
};
|
|
220
|
+
this.modeler.addPlayer(newPlayer);
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Updates the mouse position
|
|
226
|
+
* @param {Object} data
|
|
227
|
+
*/
|
|
228
|
+
updateMousePosition(data) {
|
|
229
|
+
this.clientIO.emit('cursorTrackingUpdate', {
|
|
230
|
+
roomName: this.room.getRoom(),
|
|
231
|
+
clientId: this.clientIO.id,
|
|
232
|
+
clientCursor: data,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Update Client cursor handler
|
|
237
|
+
* @param {Object} payload
|
|
238
|
+
*/
|
|
239
|
+
updateClientCursor(payload){
|
|
240
|
+
payload.clients.map(client => {
|
|
241
|
+
this.modeler.updateClientCursor(client);
|
|
242
|
+
});
|
|
201
243
|
}
|
|
202
244
|
/**
|
|
203
245
|
* Sync the modeler nodes with the microservice
|