/
element-type-hints.ts
264 lines (229 loc) · 8.61 KB
/
element-type-hints.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
/********************************************************************************
* Copyright (c) 2019-2023 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
import { GModelElementSchema } from '../model/model-schema';
import { hasArrayProp, hasBooleanProp, hasStringProp } from '../utils/type-util';
import { Action, RequestAction, ResponseAction } from './base-protocol';
/**
* Type hints are used to define what modifications are supported on the different element types.
* The rationale is to avoid a client-server round-trip for user feedback of each synchronous user interaction.
*/
export interface TypeHint {
/**
* The id of the element.
*/
readonly elementTypeId: string;
/**
* Specifies whether the element can be relocated.
*/
readonly repositionable: boolean;
/**
* Specifies whether the element can be deleted
*/
readonly deletable: boolean;
}
/**
* A {@link TypeHint} with additional modification properties for shape elements.
*/
export interface ShapeTypeHint extends TypeHint {
/**
* Specifies whether the element can be resized.
*/
readonly resizable: boolean;
/**
* Specifies whether the element can be moved to another parent
*/
readonly reparentable: boolean;
/**
* The types of elements that can be contained by this element (if unknown)
*/
readonly containableElementTypeIds?: string[];
}
/**
* A {@link TypeHint} with additional modification properties for edge elements.
*/
export interface EdgeTypeHint extends TypeHint {
/**
* Specifies whether the routing points of the edge can be changed
* i.e. edited by the user.
*/
readonly routable: boolean;
/**
* Allowed source element types for this edge type.
* If not defined unknown element can be used as source element for this edge.
*/
readonly sourceElementTypeIds?: string[];
/**
* Allowed target element types for this edge type
* If not defined unknown element can be used as target element for this edge.
*/
readonly targetElementTypeIds?: string[];
/**
* Indicates whether this type hint is dynamic or not. Dynamic edge type hints
* require an additional runtime check before creating an edge, when checking
* source and target element types is not sufficient.
*
* @see {@link RequestCheckEdgeAction}
*/
readonly dynamic?: boolean;
}
/**
* Sent from the client to the server in order to request hints on whether certain modifications are allowed for a specific element type.
* The `RequestTypeHintsAction` is optional, but should usually be among the first messages sent from the client to the server after
* receiving the model via `RequestModelAction`. The response is a {@link SetTypeHintsAction}.
* The corresponding namespace declares the action kind as constant and offers helper functions for type guard checks
* and creating new `RequestTypeHintsActions`.
*/
export interface RequestTypeHintsAction extends RequestAction<SetTypeHintsAction> {
kind: typeof RequestTypeHintsAction.KIND;
}
export namespace RequestTypeHintsAction {
export const KIND = 'requestTypeHints';
export function is(object: unknown): object is RequestTypeHintsAction {
return RequestAction.hasKind(object, KIND);
}
export function create(options: { requestId?: string } = {}): RequestTypeHintsAction {
return {
kind: KIND,
requestId: '',
...options
};
}
}
/**
* Sent from the server to the client in order to provide hints certain modifications are allowed for a specific element type.
* The corresponding namespace declares the action kind as constant and offers helper functions for type guard checks
* and creating new `SetTypeHintsActions`.
*/
export interface SetTypeHintsAction extends ResponseAction {
kind: typeof SetTypeHintsAction.KIND;
shapeHints: ShapeTypeHint[];
edgeHints: EdgeTypeHint[];
}
export namespace SetTypeHintsAction {
export const KIND = 'setTypeHints';
export function is(object: unknown): object is SetTypeHintsAction {
return Action.hasKind(object, KIND) && hasArrayProp(object, 'shapeHints') && hasArrayProp(object, 'edgeHints');
}
export function create(options: { shapeHints: ShapeTypeHint[]; edgeHints: EdgeTypeHint[]; responseId?: string }): SetTypeHintsAction {
return {
kind: KIND,
responseId: '',
...options
};
}
}
/**
* Sent from the client to the server to check wether the provided edge context information is valid i.e.
* creation of an edge with the given edge type and source/target element is allowed by the server.
* Typically this action is dispatched by edge creation tools in the creation phase of an edge that's associated
* with a dynamic {@link EdgeTypeHint}.
*/
export interface RequestCheckEdgeAction extends RequestAction<CheckEdgeResultAction> {
kind: typeof RequestCheckEdgeAction.KIND;
/**
* The element type of the edge being created.
*/
edgeType: string;
/**
* The ID of the edge source element.
*/
sourceElementId: string;
/**
* The ID of the edge target element to check.
*/
targetElementId?: string;
}
export namespace RequestCheckEdgeAction {
export const KIND = 'requestCheckEdge';
export function is(object: unknown): object is RequestCheckEdgeAction {
return (
Action.hasKind(object, KIND) &&
hasStringProp(object, 'edgeType') &&
hasStringProp(object, 'sourceElementId') &&
hasStringProp(object, 'targetElementId', true)
);
}
export function create(options: {
sourceElement: GModelElementSchema | string;
targetElement?: GModelElementSchema | string;
edgeType: string;
requestId?: string;
}): RequestCheckEdgeAction {
return {
kind: KIND,
edgeType: options.edgeType,
sourceElementId: getElementTypeId(options.sourceElement),
targetElementId: options.targetElement ? getElementTypeId(options.targetElement) : undefined,
requestId: options.requestId ?? ''
};
}
}
function getElementTypeId(element: GModelElementSchema | string): string {
if (typeof element === 'string') {
return element;
}
return element.id;
}
/**
* Send from the server to the client as a response for a {@link RequestCheckEdgeAction}. It provides
* a boolean indicating whether the edge context information provided by the corresponding request action is valid
* i.e. creation of an edge with the given edge type and source/target element is allowed.
*/
export interface CheckEdgeResultAction extends ResponseAction {
kind: typeof CheckEdgeResultAction.KIND;
/**
* true if the selected element is a valid target for this edge,
* false otherwise.
*/
isValid: boolean;
/**
* The element type of the edge that has been checked.
*/
edgeType: string;
/**
* The ID of the source element of the edge that has been checked.
*/
sourceElementId: string;
/**
* The ID of the target element of the edge that has been checked.
*/
targetElementId?: string;
}
export namespace CheckEdgeResultAction {
export const KIND = 'checkEdgeTargetResult';
export function is(object: unknown): object is CheckEdgeResultAction {
return (
Action.hasKind(object, KIND) &&
hasBooleanProp(object, 'isValid') &&
hasStringProp(object, 'edgeType') &&
hasStringProp(object, 'sourceElementId') &&
hasStringProp(object, 'targetElementId', true)
);
}
export function create(options: {
isValid: boolean;
edgeType: string;
sourceElementId: string;
targetElementId?: string;
responseId?: string;
}): CheckEdgeResultAction {
return {
kind: KIND,
responseId: '',
...options
};
}
}