@itwin/grouping-mapping-widget 0.7.0 → 0.8.0

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.
Files changed (33) hide show
  1. package/lib/cjs/widget/components/GroupPropertyAction.d.ts +1 -1
  2. package/lib/cjs/widget/components/GroupPropertyAction.js +149 -302
  3. package/lib/cjs/widget/components/GroupPropertyAction.js.map +1 -1
  4. package/lib/cjs/widget/components/GroupPropertyAction.scss +82 -8
  5. package/lib/cjs/widget/components/GroupPropertyUtils.d.ts +21 -0
  6. package/lib/cjs/widget/components/GroupPropertyUtils.js +287 -0
  7. package/lib/cjs/widget/components/GroupPropertyUtils.js.map +1 -0
  8. package/lib/cjs/widget/components/HorizontalTile.d.ts +5 -3
  9. package/lib/cjs/widget/components/HorizontalTile.js +9 -6
  10. package/lib/cjs/widget/components/HorizontalTile.js.map +1 -1
  11. package/lib/cjs/widget/components/HorizontalTile.scss +46 -22
  12. package/lib/cjs/widget/components/SelectProject.js +2 -0
  13. package/lib/cjs/widget/components/SelectProject.js.map +1 -1
  14. package/lib/cjs/widget/components/SortableHorizontalTile.d.ts +8 -0
  15. package/lib/cjs/widget/components/SortableHorizontalTile.js +51 -0
  16. package/lib/cjs/widget/components/SortableHorizontalTile.js.map +1 -0
  17. package/lib/esm/widget/components/GroupPropertyAction.d.ts +1 -1
  18. package/lib/esm/widget/components/GroupPropertyAction.js +151 -304
  19. package/lib/esm/widget/components/GroupPropertyAction.js.map +1 -1
  20. package/lib/esm/widget/components/GroupPropertyAction.scss +82 -8
  21. package/lib/esm/widget/components/GroupPropertyUtils.d.ts +21 -0
  22. package/lib/esm/widget/components/GroupPropertyUtils.js +280 -0
  23. package/lib/esm/widget/components/GroupPropertyUtils.js.map +1 -0
  24. package/lib/esm/widget/components/HorizontalTile.d.ts +5 -3
  25. package/lib/esm/widget/components/HorizontalTile.js +9 -6
  26. package/lib/esm/widget/components/HorizontalTile.js.map +1 -1
  27. package/lib/esm/widget/components/HorizontalTile.scss +46 -22
  28. package/lib/esm/widget/components/SelectProject.js +2 -0
  29. package/lib/esm/widget/components/SelectProject.js.map +1 -1
  30. package/lib/esm/widget/components/SortableHorizontalTile.d.ts +8 -0
  31. package/lib/esm/widget/components/SortableHorizontalTile.js +30 -0
  32. package/lib/esm/widget/components/SortableHorizontalTile.js.map +1 -0
  33. package/package.json +8 -3
@@ -1,16 +1,26 @@
1
- import { ContentSpecificationTypes, DefaultContentDisplayTypes, PropertyValueFormat, RelationshipMeaning, RuleTypes, } from "@itwin/presentation-common";
2
- import { Presentation } from "@itwin/presentation-frontend";
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
+ * See LICENSE.md in the project root for license terms and full copyright notice.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import { renderToStaticMarkup } from "react-dom/server";
6
+ import { PropertyValueFormat } from "@itwin/presentation-common";
3
7
  import { useActiveIModelConnection } from "@itwin/appui-react";
4
- import { SvgChevronDown, SvgChevronUp, SvgRemove, } from "@itwin/itwinui-icons-react";
5
- import { Alert, Fieldset, IconButton, LabeledInput, LabeledSelect, Select, Small, Text, } from "@itwin/itwinui-react";
8
+ import { Alert, Button, Fieldset, IconButton, Label, LabeledInput, LabeledSelect, Modal, ModalButtonBar, Small, Surface, Text, } from "@itwin/itwinui-react";
6
9
  import React, { useCallback, useEffect, useMemo, useState } from "react";
7
10
  import ActionPanel from "./ActionPanel";
8
11
  import useValidator, { NAME_REQUIREMENTS } from "../hooks/useValidator";
9
12
  import { handleError, WidgetHeader } from "./utils";
10
- import "./GroupPropertyAction.scss";
11
- import { DataType, QuantityType } from "@itwin/insights-client";
12
13
  import { useMappingClient } from "./context/MappingClientContext";
13
14
  import { useGroupingMappingApiConfig } from "./context/GroupingApiConfigContext";
15
+ import { HorizontalTile } from "./HorizontalTile";
16
+ import { DataType, QuantityType } from "@itwin/insights-client";
17
+ import { SvgClose, SvgDragHandleVertical, SvgMoreVerticalSmall, SvgRemove, SvgSearch, } from "@itwin/itwinui-icons-react";
18
+ import { closestCenter, DndContext, DragOverlay, KeyboardSensor, PointerSensor, useSensor, useSensors, } from "@dnd-kit/core";
19
+ import { arrayMove, SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy, } from "@dnd-kit/sortable";
20
+ import SortableHorizontalTile from "./SortableHorizontalTile";
21
+ import Split from "react-split";
22
+ import "./GroupPropertyAction.scss";
23
+ import { convertPresentationFields, convertToECProperties, fetchPresentationDescriptor, findProperties, } from "./GroupPropertyUtils";
14
24
  export const quantityTypesSelectionOptions = [
15
25
  { value: QuantityType.Area, label: "Area" },
16
26
  { value: QuantityType.Distance, label: "Distance" },
@@ -21,130 +31,6 @@ export const quantityTypesSelectionOptions = [
21
31
  { value: QuantityType.Volume, label: "Volume" },
22
32
  { value: QuantityType.Undefined, label: "No Quantity Type" },
23
33
  ];
24
- const extractPrimitive = (propertiesField, classToPropertiesMapping, navigation) => {
25
- var _a, _b;
26
- // There are rare cases which only happens in multiple selections where it returns more than one.
27
- // This also checks if this property comes from a navigation property
28
- const className = (_a = navigation === null || navigation === void 0 ? void 0 : navigation.rootClassName) !== null && _a !== void 0 ? _a : propertiesField.properties[0].property.classInfo.name;
29
- // Sometimes class names are not defined. Type error. Not guaranteed.
30
- if (!className) {
31
- return;
32
- }
33
- if (!classToPropertiesMapping.has(className)) {
34
- classToPropertiesMapping.set(className, []);
35
- }
36
- // Gets property name. Appends path if from navigation.
37
- const propertyName = navigation
38
- ? `${navigation.navigationName}.${propertiesField.properties[0].property.name}`
39
- : propertiesField.properties[0].property.name;
40
- const label = navigation
41
- ? `${propertiesField.label} (${navigation === null || navigation === void 0 ? void 0 : navigation.navigationName})`
42
- : propertiesField.label;
43
- // Ignore hardcoded BisCore navigation properties
44
- if (propertiesField.type.typeName === "navigation") {
45
- return;
46
- }
47
- else {
48
- (_b = classToPropertiesMapping.get(className)) === null || _b === void 0 ? void 0 : _b.push({
49
- name: propertyName,
50
- label,
51
- type: propertiesField.properties[0].property.type,
52
- });
53
- }
54
- };
55
- const extractStructProperties = (name, className, classToPropertiesMapping, members) => {
56
- var _a;
57
- for (const member of members) {
58
- if (member.type.valueFormat === PropertyValueFormat.Primitive) {
59
- if (!classToPropertiesMapping.has(className)) {
60
- classToPropertiesMapping.set(className, []);
61
- }
62
- (_a = classToPropertiesMapping.get(className)) === null || _a === void 0 ? void 0 : _a.push({
63
- name: `${name}.${member.name}`,
64
- label: member.label,
65
- type: member.type.typeName,
66
- });
67
- }
68
- else if (member.type.valueFormat === PropertyValueFormat.Struct) {
69
- extractStructProperties(`${name}.${member.name}`, className, classToPropertiesMapping, member.type.members);
70
- }
71
- }
72
- };
73
- const extractProperties = (properties, classToPropertiesMapping, navigation) => {
74
- var _a, _b;
75
- for (const property of properties) {
76
- switch (property.type.valueFormat) {
77
- case PropertyValueFormat.Primitive: {
78
- extractPrimitive(property, classToPropertiesMapping, navigation);
79
- break;
80
- }
81
- // Get structs
82
- case PropertyValueFormat.Struct: {
83
- const nestedContentField = property;
84
- // Only handling single path and not handling nested content fields within navigations
85
- if (nestedContentField.pathToPrimaryClass &&
86
- nestedContentField.pathToPrimaryClass.length > 1) {
87
- break;
88
- }
89
- switch (nestedContentField.relationshipMeaning) {
90
- case RelationshipMeaning.SameInstance: {
91
- // Check for aspects. Ignore them if coming from navigation.
92
- if (!navigation &&
93
- (nestedContentField.pathToPrimaryClass[0].relationshipInfo
94
- .name === "BisCore:ElementOwnsUniqueAspect" ||
95
- nestedContentField.pathToPrimaryClass[0].relationshipInfo
96
- .name === "BisCore:ElementOwnsMultiAspects")) {
97
- const className = nestedContentField.contentClassInfo.name;
98
- if (!classToPropertiesMapping.has(className)) {
99
- classToPropertiesMapping.set(className, []);
100
- }
101
- extractProperties(nestedContentField.nestedFields, classToPropertiesMapping, navigation);
102
- }
103
- break;
104
- }
105
- // Navigation properties
106
- case RelationshipMeaning.RelatedInstance: {
107
- if (
108
- // Deal with a TypeDefinition
109
- nestedContentField.pathToPrimaryClass[0].relationshipInfo.name ===
110
- "BisCore:GeometricElement3dHasTypeDefinition") {
111
- const className = nestedContentField.pathToPrimaryClass[0].targetClassInfo.name;
112
- extractProperties(nestedContentField.nestedFields, classToPropertiesMapping, {
113
- navigationName: "TypeDefinition",
114
- rootClassName: className,
115
- });
116
- // Hardcoded BisCore navigation properties for the type definition.
117
- (_a = classToPropertiesMapping.get(className)) === null || _a === void 0 ? void 0 : _a.push({
118
- name: "TypeDefinition.Model.ModeledElement.UserLabel",
119
- label: "Model UserLabel (TypeDefinition)",
120
- type: "string",
121
- });
122
- (_b = classToPropertiesMapping.get(className)) === null || _b === void 0 ? void 0 : _b.push({
123
- name: "TypeDefinition.Model.ModeledElement.CodeValue",
124
- label: "Model CodeValue (TypeDefinition)",
125
- type: "string",
126
- });
127
- }
128
- break;
129
- }
130
- default: {
131
- // Some elements don't have a path to primary class or relationship meaning..
132
- // Most likely a simple struct property
133
- if (!nestedContentField.pathToPrimaryClass) {
134
- const columnName = property.properties[0]
135
- .property.name;
136
- const className = property.properties[0]
137
- .property.classInfo.name;
138
- extractStructProperties(navigation
139
- ? `${navigation.navigationName}.${columnName}`
140
- : columnName, navigation ? navigation.rootClassName : className, classToPropertiesMapping, property.type.members);
141
- }
142
- }
143
- }
144
- }
145
- }
146
- }
147
- };
148
34
  const GroupPropertyAction = ({ iModelId, mappingId, groupId, groupPropertyId, groupPropertyName, keySet, returnFn, }) => {
149
35
  const iModelConnection = useActiveIModelConnection();
150
36
  const { getAccessToken } = useGroupingMappingApiConfig();
@@ -152,117 +38,75 @@ const GroupPropertyAction = ({ iModelId, mappingId, groupId, groupPropertyId, gr
152
38
  const [propertyName, setPropertyName] = useState("");
153
39
  const [dataType, setDataType] = useState(DataType.Undefined);
154
40
  const [quantityType, setQuantityType] = useState(QuantityType.Undefined);
155
- const [classToPropertiesMapping, setClassToPropertiesMapping] = useState();
156
- const [ecProperties, setEcProperties] = useState([]);
41
+ const [selectedProperties, setSelectedProperties] = useState([]);
42
+ const [propertiesMetaData, setPropertiesMetaData] = useState([]);
43
+ const [propertiesNotFoundAlert, setPropertiesNotFoundAlert] = useState(false);
157
44
  const [validator, showValidationMessage] = useValidator();
158
- const [propertyAlert, setPropertyAlert] = useState(false);
159
45
  const [isLoading, setIsLoading] = useState(false);
46
+ const [searchInput, setSearchInput] = useState("");
47
+ const [activeSearchInput, setActiveSearchInput] = useState("");
48
+ const [searched, setSearched] = useState(false);
49
+ const [activeDragProperty, setActiveDragProperty] = useState();
50
+ const sensors = useSensors(useSensor(PointerSensor), useSensor(KeyboardSensor, {
51
+ coordinateGetter: sortableKeyboardCoordinates,
52
+ }));
53
+ const [showModal, setShowModal] = useState(false);
54
+ const handleDragStart = useCallback((event) => {
55
+ const { active } = event;
56
+ const activeProperty = selectedProperties.find((p) => active.id === p.key);
57
+ setActiveDragProperty(activeProperty);
58
+ }, [selectedProperties]);
59
+ const handleDragEnd = useCallback((event) => {
60
+ const { active, over } = event;
61
+ if (over && (active.id !== over.id)) {
62
+ setSelectedProperties((items) => {
63
+ const oldIndex = selectedProperties.findIndex((p) => active.id === p.key);
64
+ const newIndex = selectedProperties.findIndex((p) => over.id === p.key);
65
+ return arrayMove(items, oldIndex, newIndex);
66
+ });
67
+ }
68
+ setActiveDragProperty(undefined);
69
+ }, [selectedProperties]);
70
+ const filteredProperties = useMemo(() => propertiesMetaData.filter((p) => [p.displayLabel, p.categoryLabel, p.actualECClassName]
71
+ .map((l) => l.toLowerCase())
72
+ .some((l) => l.includes(activeSearchInput.toLowerCase()))), [activeSearchInput, propertiesMetaData]);
160
73
  useEffect(() => {
161
- const getContent = async () => {
162
- var _a, _b, _c, _d, _e;
74
+ const generateProperties = async () => {
75
+ var _a;
163
76
  setIsLoading(true);
164
- const ruleSet = {
165
- id: "element-properties",
166
- rules: [
167
- {
168
- ruleType: RuleTypes.Content,
169
- specifications: [
170
- {
171
- specType: ContentSpecificationTypes.SelectedNodeInstances,
172
- },
173
- ],
174
- }
175
- ],
176
- };
177
- const requestOptions = {
178
- imodel: iModelConnection,
179
- keys: keySet,
180
- rulesetOrId: ruleSet,
181
- displayType: DefaultContentDisplayTypes.PropertyPane,
182
- };
183
- const content = await Presentation.presentation.getContentDescriptor(requestOptions);
184
- // Only primitives and structs for now
185
- const properties = (_a = content === null || content === void 0 ? void 0 : content.fields.filter((field) => field.type.valueFormat === PropertyValueFormat.Primitive ||
77
+ if (!iModelConnection)
78
+ return;
79
+ const descriptor = await fetchPresentationDescriptor(iModelConnection, keySet);
80
+ // Only allow primitives and structs
81
+ const propertyFields = (_a = descriptor === null || descriptor === void 0 ? void 0 : descriptor.fields.filter((field) => field.type.valueFormat === PropertyValueFormat.Primitive ||
186
82
  field.type.valueFormat === PropertyValueFormat.Struct)) !== null && _a !== void 0 ? _a : [];
187
- // Map properties to their classes
188
- const classToPropertiesMapping = new Map();
189
- extractProperties(properties, classToPropertiesMapping);
190
- const rootClassName = keySet.instanceKeys.keys().next().value;
191
- // Hardcoded BisCore navigation properties.
192
- (_b = classToPropertiesMapping.get(rootClassName)) === null || _b === void 0 ? void 0 : _b.push({
193
- name: "Model.ModeledElement.UserLabel",
194
- label: "Model UserLabel",
195
- type: "string",
196
- });
197
- (_c = classToPropertiesMapping.get(rootClassName)) === null || _c === void 0 ? void 0 : _c.push({
198
- name: "Model.ModeledElement.CodeValue",
199
- label: "Model CodeValue",
200
- type: "string",
201
- });
202
- (_d = classToPropertiesMapping.get(rootClassName)) === null || _d === void 0 ? void 0 : _d.push({
203
- name: "Category.CodeValue",
204
- label: "Category CodeValue",
205
- type: "string",
206
- });
207
- (_e = classToPropertiesMapping.get(rootClassName)) === null || _e === void 0 ? void 0 : _e.push({
208
- name: "Category.UserLabel",
209
- label: "Category UserLabel",
210
- type: "string",
211
- });
212
- setClassToPropertiesMapping(classToPropertiesMapping);
213
- let newEcProperties;
214
- // Fetch already existing ec properties then add all classes from presentation
83
+ const propertiesMetaData = convertPresentationFields(propertyFields);
84
+ setPropertiesMetaData(propertiesMetaData);
215
85
  if (groupPropertyId) {
216
86
  const accessToken = await getAccessToken();
217
87
  let response;
218
88
  try {
219
89
  response = await mappingClient.getGroupProperty(accessToken, iModelId, mappingId, groupId, groupPropertyId);
90
+ setPropertyName(response.propertyName);
91
+ setDataType(response.dataType);
92
+ setQuantityType(response.quantityType);
93
+ const properties = findProperties(response.ecProperties, propertiesMetaData);
94
+ if (properties.length === 0) {
95
+ setPropertiesNotFoundAlert(true);
96
+ }
97
+ setSelectedProperties(properties);
220
98
  }
221
99
  catch (error) {
222
100
  handleError(error.status);
223
101
  }
224
- if (!response) {
225
- return;
226
- }
227
- newEcProperties = response.ecProperties;
228
- let keys = Array.from(classToPropertiesMapping.keys()).reverse();
229
- for (const ecProperty of newEcProperties) {
230
- keys = keys.filter((key) => `${ecProperty.ecSchemaName}:${ecProperty.ecClassName}` !== key);
231
- }
232
- newEcProperties.push(...keys.map((key) => ({
233
- ecSchemaName: key.split(":")[0],
234
- ecClassName: key.split(":")[1],
235
- // Placeholders for properties
236
- ecPropertyName: "",
237
- ecPropertyType: DataType.Undefined,
238
- })));
239
- setPropertyName(response.propertyName);
240
- setDataType(response.dataType);
241
- setQuantityType(response.quantityType);
242
102
  }
243
- else {
244
- newEcProperties = Array.from(classToPropertiesMapping)
245
- .map(([key]) => ({
246
- ecSchemaName: key.split(":")[0],
247
- ecClassName: key.split(":")[1],
248
- // Placeholders for properties
249
- ecPropertyName: "",
250
- ecPropertyType: DataType.Undefined,
251
- }))
252
- .reverse();
253
- }
254
- setEcProperties(newEcProperties);
255
103
  setIsLoading(false);
256
104
  };
257
- void getContent();
105
+ void generateProperties();
258
106
  }, [getAccessToken, mappingClient, groupId, groupPropertyId, iModelConnection, iModelId, keySet, mappingId]);
259
107
  const onSave = async () => {
260
- const filteredEcProperties = ecProperties.filter((ecProperty) => ecProperty.ecPropertyName && ecProperty.ecPropertyType);
261
- if (!filteredEcProperties.length || !validator.allValid()) {
108
+ if (!validator.allValid()) {
262
109
  showValidationMessage(true);
263
- if (!filteredEcProperties.length) {
264
- setPropertyAlert(true);
265
- }
266
110
  return;
267
111
  }
268
112
  try {
@@ -272,7 +116,7 @@ const GroupPropertyAction = ({ iModelId, mappingId, groupId, groupPropertyId, gr
272
116
  propertyName,
273
117
  dataType,
274
118
  quantityType,
275
- ecProperties: filteredEcProperties,
119
+ ecProperties: selectedProperties.map((p) => convertToECProperties(p)).flat(),
276
120
  };
277
121
  groupPropertyId
278
122
  ? await mappingClient.updateGroupProperty(accessToken, iModelId, mappingId, groupId, groupPropertyId, groupProperty)
@@ -284,52 +128,29 @@ const GroupPropertyAction = ({ iModelId, mappingId, groupId, groupPropertyId, gr
284
128
  setIsLoading(false);
285
129
  }
286
130
  };
287
- const onChange = useCallback((value, index) => {
288
- setPropertyAlert(false);
289
- const property = JSON.parse(value);
290
- setEcProperties((ecProperties) => {
291
- const updatedEcProperties = [...ecProperties];
292
- updatedEcProperties[index].ecPropertyName = property.name;
293
- // Unique types
294
- let type = DataType.Undefined;
295
- switch (property.type) {
296
- case "long":
297
- type = DataType.Integer;
298
- break;
299
- default:
300
- type = property.type;
301
- }
302
- updatedEcProperties[index].ecPropertyType = type;
303
- return updatedEcProperties;
304
- });
131
+ const startSearch = useCallback(() => {
132
+ if (!searchInput)
133
+ return;
134
+ setActiveSearchInput(searchInput);
135
+ setSearched(true);
136
+ }, [searchInput]);
137
+ const clearSearch = useCallback(() => {
138
+ setSearchInput("");
139
+ setActiveSearchInput("");
140
+ setSearched(false);
305
141
  }, []);
306
- const propertyOptions = useMemo(() => {
307
- return ecProperties.map((ecProperty) => {
308
- var _a, _b;
309
- return (_b = (_a = classToPropertiesMapping === null || classToPropertiesMapping === void 0 ? void 0 : classToPropertiesMapping.get(`${ecProperty.ecSchemaName}:${ecProperty.ecClassName}`)) === null || _a === void 0 ? void 0 : _a.map((property) => ({
310
- value: JSON.stringify({
311
- name: property.name,
312
- type: property.type,
313
- }),
314
- label: property.label,
315
- }))) !== null && _b !== void 0 ? _b : [];
316
- });
317
- }, [classToPropertiesMapping, ecProperties]);
318
- const getValue = useCallback((ecProperty, index) => {
319
- var _a;
320
- const property = (_a = classToPropertiesMapping === null || classToPropertiesMapping === void 0 ? void 0 : classToPropertiesMapping.get(`${ecProperty.ecSchemaName}:${ecProperty.ecClassName}`)) === null || _a === void 0 ? void 0 : _a.find((property) => property.name === ecProperties[index].ecPropertyName);
321
- const result = JSON.stringify({
322
- name: property === null || property === void 0 ? void 0 : property.name,
323
- type: property === null || property === void 0 ? void 0 : property.type,
324
- });
325
- return result;
326
- }, [classToPropertiesMapping, ecProperties]);
327
- return (React.createElement(React.Fragment, null,
142
+ useEffect(() => {
143
+ if (searchInput.length === 0) {
144
+ setSearched(false);
145
+ clearSearch();
146
+ }
147
+ }, [searchInput, setSearched, clearSearch]);
148
+ return (React.createElement(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragStart: handleDragStart, onDragEnd: handleDragEnd },
328
149
  React.createElement(WidgetHeader, { title: groupPropertyName !== null && groupPropertyName !== void 0 ? groupPropertyName : "Add Property", returnFn: async () => returnFn(false) }),
329
150
  React.createElement("div", { className: 'gmw-group-property-action-container' },
330
- React.createElement(Fieldset, { className: 'gmw-property-options', legend: 'Property Details' },
151
+ React.createElement(Fieldset, { disabled: isLoading, className: 'gmw-property-options', legend: 'Property Details' },
331
152
  React.createElement(Small, { className: 'gmw-field-legend' }, "Asterisk * indicates mandatory fields."),
332
- React.createElement(LabeledInput, { id: 'propertyName', label: 'Property Name', value: propertyName, required: true, disabled: isLoading, onChange: (event) => {
153
+ React.createElement(LabeledInput, { id: 'propertyName', label: 'Property Name', value: propertyName, required: true, onChange: (event) => {
333
154
  setPropertyName(event.target.value);
334
155
  validator.showMessageFor("propertyName");
335
156
  }, message: validator.message("propertyName", propertyName, NAME_REQUIREMENTS), status: validator.message("propertyName", propertyName, NAME_REQUIREMENTS)
@@ -337,7 +158,7 @@ const GroupPropertyAction = ({ iModelId, mappingId, groupId, groupPropertyId, gr
337
158
  : undefined, onBlur: () => {
338
159
  validator.showMessageFor("propertyName");
339
160
  } }),
340
- React.createElement(LabeledSelect, { label: "Data Type", id: 'dataType', disabled: isLoading, options: [
161
+ React.createElement(LabeledSelect, { label: "Data Type", id: 'dataType', options: [
341
162
  { value: DataType.Boolean, label: "Boolean" },
342
163
  { value: DataType.Number, label: "Number" },
343
164
  { value: DataType.String, label: "String" },
@@ -349,45 +170,71 @@ const GroupPropertyAction = ({ iModelId, mappingId, groupId, groupPropertyId, gr
349
170
  : undefined, onBlur: () => {
350
171
  validator.showMessageFor("dataType");
351
172
  }, onShow: () => { }, onHide: () => { } }),
352
- React.createElement(LabeledSelect, { label: 'Quantity Type', disabled: isLoading, options: quantityTypesSelectionOptions, value: quantityType, onChange: setQuantityType, onShow: () => { }, onHide: () => { } })),
353
- React.createElement(Fieldset, { className: 'gmw-property-selection-container', legend: 'Properties' },
354
- propertyAlert && (React.createElement(Alert, { type: "negative" }, "Please select at least one property.")),
355
- isLoading &&
356
- Array(3)
357
- .fill(null)
358
- .map((_, index) => (React.createElement(Text, { key: index, variant: 'headline', isSkeleton: true }, "LOADING SKELETON"))),
359
- ecProperties.map((ecProperty, index) => {
360
- return (React.createElement("div", { className: 'gmw-property-select-item', key: `${ecProperty.ecSchemaName}${ecProperty.ecClassName}` },
361
- React.createElement(Text, { variant: 'leading' }, ecProperty.ecClassName),
362
- React.createElement(Text, { isMuted: true, variant: 'small' }, ecProperty.ecSchemaName),
363
- React.createElement("div", { className: 'gmw-selection-and-reorder' },
364
- React.createElement(Select, { options: propertyOptions[index], value: getValue(ecProperty, index), onChange: (value) => { value && onChange(value, index); }, placeholder: "<No Property Mapped>", style: { width: "100%" }, onShow: () => { }, onHide: () => { } }),
365
- React.createElement(IconButton, { onClick: () => {
366
- const updatedEcPropertyList = [...ecProperties];
367
- updatedEcPropertyList[index] = {
368
- ...updatedEcPropertyList[index],
369
- ecPropertyName: "",
370
- ecPropertyType: DataType.Undefined,
371
- };
372
- setEcProperties(updatedEcPropertyList);
373
- }, disabled: !ecProperty.ecPropertyName && !ecProperty.ecPropertyType },
374
- React.createElement(SvgRemove, null)),
375
- React.createElement(IconButton, { onClick: () => {
376
- const tab = [...ecProperties];
377
- const item = tab.splice(index, 1);
378
- tab.splice(index - 1, 0, item[0]);
379
- setEcProperties(tab);
380
- }, disabled: index === 0 },
381
- React.createElement(SvgChevronUp, null)),
382
- React.createElement(IconButton, { onClick: () => {
383
- const tab = [...ecProperties];
384
- const item = tab.splice(index, 1);
385
- tab.splice(index + 1, 0, item[0]);
386
- setEcProperties(tab);
387
- }, disabled: index === ecProperties.length - 1 },
388
- React.createElement(SvgChevronDown, null)))));
389
- }))),
390
- React.createElement(ActionPanel, { onSave: onSave, onCancel: async () => returnFn(false), isLoading: isLoading })));
173
+ React.createElement(LabeledSelect, { label: 'Quantity Type', options: quantityTypesSelectionOptions, value: quantityType, onChange: setQuantityType, onShow: () => { }, onHide: () => { } })),
174
+ propertiesNotFoundAlert &&
175
+ React.createElement(Alert, { type: "warning" }, "Warning: Could not match saved properties from the current generated list. It does not confirm or deny validity. Overwriting will occur if a new selection is made and saved."),
176
+ React.createElement(Fieldset, { className: 'gmw-property-view-container', legend: "Mapped Properties" },
177
+ React.createElement("div", { className: "gmw-property-view-button" },
178
+ React.createElement(Button, { onClick: async () => setShowModal(true), disabled: isLoading }, "Select Properties")),
179
+ React.createElement("div", { className: "gmw-properties-list" }, selectedProperties.length === 0 && !isLoading ?
180
+ React.createElement("div", { className: "gmw-empty-selection" },
181
+ React.createElement(Text, null, "No properties selected."),
182
+ React.createElement(Text, null, "Press the \"Select Properties\" button for options.")) :
183
+ selectedProperties.map((property) => (React.createElement(HorizontalTile, { key: property.key, title: `${property.displayLabel} (${property.propertyType})`, titleTooltip: `${property.actualECClassName}`, subText: property.categoryLabel, actionGroup: null })))))),
184
+ React.createElement(ActionPanel, { onSave: onSave, onCancel: async () => returnFn(false), isLoading: isLoading, isSavingDisabled: selectedProperties.length === 0 || !propertyName || !dataType }),
185
+ React.createElement(Modal, { title: "Properties Selection", isOpen: showModal, onClose: () => {
186
+ setShowModal(false);
187
+ clearSearch();
188
+ }, closeOnExternalClick: false },
189
+ React.createElement(Split, { expandToMin: false, className: "gmw-property-selection-container", gutterAlign: "center", gutterSize: 2, gutter: () => {
190
+ // Expects HTMLElement
191
+ const dragHangle = renderToStaticMarkup(React.createElement("div", { className: "gmw-gutter-drag-icon" },
192
+ React.createElement(SvgMoreVerticalSmall, null)));
193
+ const gutter = document.createElement("div");
194
+ gutter.className = `gmw-gutter`;
195
+ gutter.innerHTML = dragHangle;
196
+ return gutter;
197
+ }, direction: "horizontal" },
198
+ React.createElement(Surface, { className: "gmw-available-properties", elevation: 1 },
199
+ React.createElement("div", { className: "gmw-available-properties-header" },
200
+ React.createElement(Label, { as: "span" }, "Available Properties"),
201
+ React.createElement(LabeledInput, { displayStyle: "inline", iconDisplayStyle: "inline", className: "gmw-available-prop-search", value: searchInput, size: "small", placeholder: "Search....", onChange: (event) => {
202
+ const { target: { value }, } = event;
203
+ setSearchInput(value);
204
+ }, onKeyDown: (event) => {
205
+ if (event.key === "Enter") {
206
+ startSearch();
207
+ }
208
+ }, svgIcon: searched ? (React.createElement(IconButton, { onClick: clearSearch, styleType: "borderless" },
209
+ React.createElement(SvgClose, null))) : (React.createElement(IconButton, { onClick: startSearch, styleType: "borderless" },
210
+ React.createElement(SvgSearch, null))) })),
211
+ filteredProperties.length === 0 ?
212
+ React.createElement("div", { className: "gmw-empty-selection" },
213
+ React.createElement(Text, null, "No properties available. ")) :
214
+ React.createElement("div", { className: "gmw-properties-list" }, filteredProperties.map((property) => (React.createElement(HorizontalTile, { key: property.key, title: `${property.displayLabel} (${property.propertyType})`, titleTooltip: `${property.actualECClassName}`, subText: property.categoryLabel, actionGroup: null, selected: selectedProperties.some((p) => property.key === p.key), onClick: () => setSelectedProperties((sp) => sp.some((p) => property.key === p.key)
215
+ ? sp.filter((p) => property.key !== p.key)
216
+ : [...sp, property]) }))))),
217
+ React.createElement(Surface, { className: "gmw-selected-properties", elevation: 1 },
218
+ React.createElement(Label, { as: "span" }, "Selected Properties"),
219
+ selectedProperties.length === 0 ?
220
+ React.createElement("div", { className: "gmw-empty-selection" },
221
+ React.createElement(Text, null, "No properties selected."),
222
+ React.createElement(Text, null, "Add some by clicking on the properties shown left.")) :
223
+ React.createElement("div", { className: "gmw-properties-list" },
224
+ React.createElement(SortableContext, { items: selectedProperties.map((p) => p.key), strategy: verticalListSortingStrategy }, selectedProperties.map((property) => React.createElement(SortableHorizontalTile, { key: property.key, id: property.key, title: `${property.displayLabel} (${property.propertyType})`, titleTooltip: `${property.actualECClassName}`, subText: property.categoryLabel, actionGroup: React.createElement("div", null,
225
+ React.createElement(IconButton, { styleType: "borderless", title: "Remove", onClick: () => {
226
+ setSelectedProperties((sp) => sp.filter((p) => property.key !== p.key));
227
+ } },
228
+ React.createElement(SvgRemove, null))) })))))),
229
+ React.createElement(ModalButtonBar, null,
230
+ React.createElement(Button, { onClick: () => {
231
+ setShowModal(false);
232
+ clearSearch();
233
+ }, styleType: "high-visibility" }, "Close"))),
234
+ React.createElement(DragOverlay, { zIndex: 9999 }, activeDragProperty ?
235
+ React.createElement(HorizontalTile, { title: `${activeDragProperty.displayLabel} (${activeDragProperty.propertyType})`, titleTooltip: `${activeDragProperty.actualECClassName}`, subText: activeDragProperty.categoryLabel, actionGroup: React.createElement(IconButton, { styleType: "borderless" },
236
+ React.createElement(SvgRemove, null)), dragHandle: React.createElement("div", { className: "gmw-drag-icon" },
237
+ React.createElement(SvgDragHandleVertical, null)) }) : null)));
391
238
  };
392
239
  export default GroupPropertyAction;
393
240
  //# sourceMappingURL=GroupPropertyAction.js.map