commons-shared-web-ui 0.0.63 → 0.0.64
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.
|
@@ -5334,7 +5334,7 @@ class SmartFormComponent {
|
|
|
5334
5334
|
if (!rawCfg)
|
|
5335
5335
|
return of([]);
|
|
5336
5336
|
const cfg = this._normalizeHierarchyCfg(rawCfg);
|
|
5337
|
-
if (!cfg.templateApiUrl)
|
|
5337
|
+
if (!cfg.templateApiUrl && !cfg.templateData)
|
|
5338
5338
|
return of([]);
|
|
5339
5339
|
return this._fetchHierarchyTemplate(cfg).pipe(map((template) => template ? this._buildHierarchyFields(cfg, template) : []), catchError(() => of([])));
|
|
5340
5340
|
}
|
|
@@ -5351,6 +5351,8 @@ class SmartFormComponent {
|
|
|
5351
5351
|
templateSelect: ta['select'] || 'default',
|
|
5352
5352
|
templateSelectField: ta['selectField'] || 'isDefault',
|
|
5353
5353
|
templateSelectCode: ta['selectCode'],
|
|
5354
|
+
templateSelectId: ta['selectId'],
|
|
5355
|
+
templateData: ta['data'],
|
|
5354
5356
|
rootCodePath: st['rootCodePath'] || 'rootClassCode',
|
|
5355
5357
|
templateCodePath: st['templateCodePath'] || 'templateCode',
|
|
5356
5358
|
hierarchyListPath: st['hierarchyListPath'] || 'mdmclasshierarchytemplatestructList',
|
|
@@ -5398,6 +5400,11 @@ class SmartFormComponent {
|
|
|
5398
5400
|
};
|
|
5399
5401
|
}
|
|
5400
5402
|
_fetchHierarchyTemplate(cfg) {
|
|
5403
|
+
// Caller already resolved the exact template object — use it as-is, skipping the HTTP GET
|
|
5404
|
+
// and the templateSelect/templateSelectId matching entirely (there's nothing left to pick
|
|
5405
|
+
// between). See HierarchyCfg.templateData for the staleness tradeoff this accepts.
|
|
5406
|
+
if (cfg.templateData)
|
|
5407
|
+
return of(cfg.templateData);
|
|
5401
5408
|
const headers = this.getHeaders();
|
|
5402
5409
|
return this.http.get(cfg.templateApiUrl, { headers }).pipe(map((response) => {
|
|
5403
5410
|
let list;
|
|
@@ -5417,6 +5424,15 @@ class SmartFormComponent {
|
|
|
5417
5424
|
if (cfg.templateSelect === 'byCode') {
|
|
5418
5425
|
return list.find((t) => this._getPathValue(t, cfg.templateCodePath) === cfg.templateSelectCode) || list[0];
|
|
5419
5426
|
}
|
|
5427
|
+
if (cfg.templateSelect === 'byId') {
|
|
5428
|
+
// Multiple templates can share the same templateCode (distinguished by templateName,
|
|
5429
|
+
// with one flagged isDefault) — 'byCode' alone can't disambiguate between them, so this
|
|
5430
|
+
// matches the exact template the admin picked by its unique numeric id instead. Falls
|
|
5431
|
+
// back to the tenant default (then list[0]) if the id no longer matches anything.
|
|
5432
|
+
return list.find((t) => t.id === cfg.templateSelectId)
|
|
5433
|
+
|| list.find((t) => !!t[cfg.templateSelectField])
|
|
5434
|
+
|| list[0];
|
|
5435
|
+
}
|
|
5420
5436
|
return list.find((t) => !!t[cfg.templateSelectField]) || list[0];
|
|
5421
5437
|
}), catchError(() => of(null)));
|
|
5422
5438
|
}
|
|
@@ -8173,6 +8189,8 @@ class FormSchemaTreeService {
|
|
|
8173
8189
|
'GENERATED': 'generated',
|
|
8174
8190
|
'CHIP': 'chip',
|
|
8175
8191
|
'LOCATION': 'location',
|
|
8192
|
+
'GEOGRAPHY_DYNAMIC': 'geography',
|
|
8193
|
+
'GEOGRAPHY_NODE': 'geographyNode',
|
|
8176
8194
|
'GROUP': 'group',
|
|
8177
8195
|
'SUBFIELDS': 'section',
|
|
8178
8196
|
};
|
|
@@ -8237,11 +8255,11 @@ class FormSchemaTreeService {
|
|
|
8237
8255
|
else if (child.type === 'ROW' && child.children?.length) {
|
|
8238
8256
|
// ROW children are leaf fields
|
|
8239
8257
|
for (const rowChild of child.children) {
|
|
8240
|
-
leafFields.push(this.
|
|
8258
|
+
leafFields.push(...this._buildFieldNodesFor(rowChild));
|
|
8241
8259
|
}
|
|
8242
8260
|
}
|
|
8243
8261
|
else {
|
|
8244
|
-
leafFields.push(this.
|
|
8262
|
+
leafFields.push(...this._buildFieldNodesFor(child));
|
|
8245
8263
|
}
|
|
8246
8264
|
}
|
|
8247
8265
|
// Flush remaining leaf fields
|
|
@@ -8260,11 +8278,11 @@ class FormSchemaTreeService {
|
|
|
8260
8278
|
}
|
|
8261
8279
|
else if (child.type === 'ROW' && child.children?.length) {
|
|
8262
8280
|
for (const rowChild of child.children) {
|
|
8263
|
-
fields.push(this.
|
|
8281
|
+
fields.push(...this._buildFieldNodesFor(rowChild));
|
|
8264
8282
|
}
|
|
8265
8283
|
}
|
|
8266
8284
|
else {
|
|
8267
|
-
fields.push(this.
|
|
8285
|
+
fields.push(...this._buildFieldNodesFor(child));
|
|
8268
8286
|
}
|
|
8269
8287
|
}
|
|
8270
8288
|
const isVisible = field.isEnabled ?? field.visible ?? true;
|
|
@@ -8296,6 +8314,38 @@ class FormSchemaTreeService {
|
|
|
8296
8314
|
isLocked: field.readonly === true,
|
|
8297
8315
|
};
|
|
8298
8316
|
}
|
|
8317
|
+
/**
|
|
8318
|
+
* Normal leaf fields produce exactly one SelectionFieldNode. A GEOGRAPHY_DYNAMIC field is
|
|
8319
|
+
* special-cased: it expands into the whole-block toggle PLUS one synthetic toggle per
|
|
8320
|
+
* hierarchy level declared in geographyConfig.field.nodes (e.g. Country/State/District), so a
|
|
8321
|
+
* business user can show/hide individual levels instead of only the entire address block.
|
|
8322
|
+
* This is purely additive to every other field type's tree — see _applyGeographyNodeSelections
|
|
8323
|
+
* for the matching write-back half.
|
|
8324
|
+
*/
|
|
8325
|
+
_buildFieldNodesFor(field) {
|
|
8326
|
+
if (field.type === 'GEOGRAPHY_DYNAMIC') {
|
|
8327
|
+
return this._buildGeographyFieldNodes(field);
|
|
8328
|
+
}
|
|
8329
|
+
return [this._buildFieldNode(field)];
|
|
8330
|
+
}
|
|
8331
|
+
/** See _buildFieldNodesFor. Synthetic per-level nodes are ephemeral (rebuilt on every parse from
|
|
8332
|
+
* geographyConfig.field.nodes) — they don't exist as real schema children, only as a nested map
|
|
8333
|
+
* on the parent GEOGRAPHY_DYNAMIC field, so they carry a distinguishing `name` for name-keyed
|
|
8334
|
+
* matching in _applyGeographyNodeSelections rather than object identity. */
|
|
8335
|
+
_buildGeographyFieldNodes(field) {
|
|
8336
|
+
const nodes = [this._buildFieldNode(field)];
|
|
8337
|
+
const geoNodes = field.geographyConfig?.field?.nodes ?? {};
|
|
8338
|
+
for (const classCode of Object.keys(geoNodes)) {
|
|
8339
|
+
const cfg = geoNodes[classCode] ?? {};
|
|
8340
|
+
const synthetic = {
|
|
8341
|
+
name: `${field.name}__node__${classCode}`,
|
|
8342
|
+
label: cfg.label ?? classCode,
|
|
8343
|
+
type: 'GEOGRAPHY_NODE',
|
|
8344
|
+
};
|
|
8345
|
+
nodes.push({ fieldConfig: synthetic, selected: cfg.hidden !== true, isLocked: false });
|
|
8346
|
+
}
|
|
8347
|
+
return nodes;
|
|
8348
|
+
}
|
|
8299
8349
|
// ────────────────────────────────────────────────────────────────────────────
|
|
8300
8350
|
// PRIVATE — Apply selection back to FormSchema children
|
|
8301
8351
|
// ────────────────────────────────────────────────────────────────────────────
|
|
@@ -8335,6 +8385,9 @@ class FormSchemaTreeService {
|
|
|
8335
8385
|
rowChild.visible = matchedField.selected; // Backward compatibility
|
|
8336
8386
|
fieldIdx++;
|
|
8337
8387
|
}
|
|
8388
|
+
if (rowChild.type === 'GEOGRAPHY_DYNAMIC') {
|
|
8389
|
+
this._applyGeographyNodeSelections(sections, rowChild);
|
|
8390
|
+
}
|
|
8338
8391
|
}
|
|
8339
8392
|
}
|
|
8340
8393
|
else {
|
|
@@ -8344,9 +8397,39 @@ class FormSchemaTreeService {
|
|
|
8344
8397
|
child.visible = matchedField.selected; // Backward compatibility
|
|
8345
8398
|
fieldIdx++;
|
|
8346
8399
|
}
|
|
8400
|
+
if (child.type === 'GEOGRAPHY_DYNAMIC') {
|
|
8401
|
+
this._applyGeographyNodeSelections(sections, child);
|
|
8402
|
+
}
|
|
8347
8403
|
}
|
|
8348
8404
|
}
|
|
8349
8405
|
}
|
|
8406
|
+
/**
|
|
8407
|
+
* Writes each per-level checkbox state (from the synthetic `${field.name}__node__${classCode}`
|
|
8408
|
+
* entries built by _buildGeographyFieldNodes) back onto the real GEOGRAPHY_DYNAMIC field's
|
|
8409
|
+
* nested `geographyConfig.field.nodes[classCode].hidden`. The whole-block toggle itself is
|
|
8410
|
+
* already handled by the normal name-matched assignment at the call site above — this only
|
|
8411
|
+
* covers the additional per-level entries, which have no corresponding real schema child.
|
|
8412
|
+
*/
|
|
8413
|
+
_applyGeographyNodeSelections(sections, field) {
|
|
8414
|
+
const geoNodes = field.geographyConfig?.field?.nodes;
|
|
8415
|
+
if (!geoNodes)
|
|
8416
|
+
return;
|
|
8417
|
+
for (const classCode of Object.keys(geoNodes)) {
|
|
8418
|
+
const nodeField = this._findSelectionFieldByName(sections, `${field.name}__node__${classCode}`);
|
|
8419
|
+
if (nodeField) {
|
|
8420
|
+
geoNodes[classCode] = { ...geoNodes[classCode], hidden: !nodeField.selected };
|
|
8421
|
+
}
|
|
8422
|
+
}
|
|
8423
|
+
}
|
|
8424
|
+
_findSelectionFieldByName(sections, name) {
|
|
8425
|
+
for (const section of sections) {
|
|
8426
|
+
for (const f of section.fields) {
|
|
8427
|
+
if (f.fieldConfig.name === name)
|
|
8428
|
+
return f;
|
|
8429
|
+
}
|
|
8430
|
+
}
|
|
8431
|
+
return null;
|
|
8432
|
+
}
|
|
8350
8433
|
_applyFieldsToChildren(selectionFields, children) {
|
|
8351
8434
|
let fi = 0;
|
|
8352
8435
|
for (const child of children) {
|
|
@@ -8354,22 +8437,40 @@ class FormSchemaTreeService {
|
|
|
8354
8437
|
continue;
|
|
8355
8438
|
if (child.type === 'ROW' && child.children?.length) {
|
|
8356
8439
|
for (const rowChild of child.children) {
|
|
8357
|
-
|
|
8358
|
-
rowChild.isEnabled = selectionFields[fi].selected;
|
|
8359
|
-
rowChild.visible = selectionFields[fi].selected; // Backward compatibility
|
|
8360
|
-
fi++;
|
|
8361
|
-
}
|
|
8440
|
+
fi = this._applyOneFieldSelection(selectionFields, rowChild, fi);
|
|
8362
8441
|
}
|
|
8363
8442
|
}
|
|
8364
8443
|
else {
|
|
8365
|
-
|
|
8366
|
-
child.isEnabled = selectionFields[fi].selected;
|
|
8367
|
-
child.visible = selectionFields[fi].selected; // Backward compatibility
|
|
8368
|
-
fi++;
|
|
8369
|
-
}
|
|
8444
|
+
fi = this._applyOneFieldSelection(selectionFields, child, fi);
|
|
8370
8445
|
}
|
|
8371
8446
|
}
|
|
8372
8447
|
}
|
|
8448
|
+
/**
|
|
8449
|
+
* Applies the selection state for exactly one schema child at flat position `fi` in
|
|
8450
|
+
* `selectionFields`, and returns the next unconsumed index. Normally that's 1 slot — but
|
|
8451
|
+
* _buildGeographyFieldNodes emits (1 whole-block + 1 per hierarchy level) entries for a single
|
|
8452
|
+
* GEOGRAPHY_DYNAMIC schema child, so this must consume that many slots here too, or every
|
|
8453
|
+
* subsequent sibling field's selection state would read from the wrong (shifted) index.
|
|
8454
|
+
*/
|
|
8455
|
+
_applyOneFieldSelection(selectionFields, child, fi) {
|
|
8456
|
+
if (fi < selectionFields.length) {
|
|
8457
|
+
child.isEnabled = selectionFields[fi].selected;
|
|
8458
|
+
child.visible = selectionFields[fi].selected; // Backward compatibility
|
|
8459
|
+
}
|
|
8460
|
+
let consumed = 1;
|
|
8461
|
+
if (child.type === 'GEOGRAPHY_DYNAMIC') {
|
|
8462
|
+
const geoNodes = child.geographyConfig?.field?.nodes ?? {};
|
|
8463
|
+
const classCodes = Object.keys(geoNodes);
|
|
8464
|
+
classCodes.forEach((classCode, i) => {
|
|
8465
|
+
const nodeField = selectionFields[fi + 1 + i];
|
|
8466
|
+
if (nodeField) {
|
|
8467
|
+
geoNodes[classCode] = { ...geoNodes[classCode], hidden: !nodeField.selected };
|
|
8468
|
+
}
|
|
8469
|
+
});
|
|
8470
|
+
consumed += classCodes.length;
|
|
8471
|
+
}
|
|
8472
|
+
return fi + consumed;
|
|
8473
|
+
}
|
|
8373
8474
|
_findSelectionField(sections, _field, _index) {
|
|
8374
8475
|
// Flatten all fields from all sections
|
|
8375
8476
|
for (const section of sections) {
|
|
@@ -8397,12 +8498,12 @@ class FormSchemaTreeService {
|
|
|
8397
8498
|
else if (child.type === 'ROW' && child.children?.length) {
|
|
8398
8499
|
child.children.forEach((rowChild, ri) => {
|
|
8399
8500
|
if (rowChild.isEnabled !== false && rowChild.visible !== false) {
|
|
8400
|
-
children.push(this.
|
|
8501
|
+
children.push(this._buildConfiguratorLeafNode(rowChild, [...childPath, ri]));
|
|
8401
8502
|
}
|
|
8402
8503
|
});
|
|
8403
8504
|
}
|
|
8404
8505
|
else {
|
|
8405
|
-
children.push(this.
|
|
8506
|
+
children.push(this._buildConfiguratorLeafNode(child, childPath));
|
|
8406
8507
|
}
|
|
8407
8508
|
});
|
|
8408
8509
|
return {
|
|
@@ -8428,12 +8529,12 @@ class FormSchemaTreeService {
|
|
|
8428
8529
|
else if (child.type === 'ROW' && child.children?.length) {
|
|
8429
8530
|
child.children.forEach((rowChild, ri) => {
|
|
8430
8531
|
if (rowChild.isEnabled !== false && rowChild.visible !== false) {
|
|
8431
|
-
children.push(this.
|
|
8532
|
+
children.push(this._buildConfiguratorLeafNode(rowChild, [...childPath, ri]));
|
|
8432
8533
|
}
|
|
8433
8534
|
});
|
|
8434
8535
|
}
|
|
8435
8536
|
else {
|
|
8436
|
-
children.push(this.
|
|
8537
|
+
children.push(this._buildConfiguratorLeafNode(child, childPath));
|
|
8437
8538
|
}
|
|
8438
8539
|
});
|
|
8439
8540
|
return {
|
|
@@ -8457,6 +8558,61 @@ class FormSchemaTreeService {
|
|
|
8457
8558
|
children: [],
|
|
8458
8559
|
};
|
|
8459
8560
|
}
|
|
8561
|
+
/** Dispatches to the GEOGRAPHY_DYNAMIC-aware builder when needed; otherwise a normal leaf node. */
|
|
8562
|
+
_buildConfiguratorLeafNode(field, path) {
|
|
8563
|
+
if (field.type === 'GEOGRAPHY_DYNAMIC') {
|
|
8564
|
+
return this._buildGeographyConfiguratorNode(field, path);
|
|
8565
|
+
}
|
|
8566
|
+
return this._buildConfiguratorFieldNode(field, path);
|
|
8567
|
+
}
|
|
8568
|
+
/**
|
|
8569
|
+
* Builds the Configurator tree entry for a GEOGRAPHY_DYNAMIC field ("Address"): the field
|
|
8570
|
+
* itself stays selectable/editable as normal (its own label/colSpan/etc.), but it ALSO gets
|
|
8571
|
+
* one synthetic child per hierarchy level declared in geographyConfig.field.nodes (skipping
|
|
8572
|
+
* any the admin already hid via Field Selection), so each level's own label can be
|
|
8573
|
+
* individually edited. These children share the parent's `path` (there's no real schema
|
|
8574
|
+
* array index for a nested map entry) — `geoClassCode` is what actually identifies which
|
|
8575
|
+
* one a selection/patch targets. See FieldConfiguratorService for the read/write side.
|
|
8576
|
+
*/
|
|
8577
|
+
_buildGeographyConfiguratorNode(field, path) {
|
|
8578
|
+
const geoNodes = field.geographyConfig?.field?.nodes ?? {};
|
|
8579
|
+
const children = Object.keys(geoNodes)
|
|
8580
|
+
.filter((code) => geoNodes[code]?.hidden !== true)
|
|
8581
|
+
.map((code) => ({
|
|
8582
|
+
id: `${path.join('-')}__geo__${code}`,
|
|
8583
|
+
label: geoNodes[code]?.label || code,
|
|
8584
|
+
type: 'field',
|
|
8585
|
+
expanded: false,
|
|
8586
|
+
fieldConfig: null,
|
|
8587
|
+
path,
|
|
8588
|
+
children: [],
|
|
8589
|
+
geoClassCode: code,
|
|
8590
|
+
}));
|
|
8591
|
+
return {
|
|
8592
|
+
id: field.name || `field-${path.join('-')}`,
|
|
8593
|
+
label: field.label || field.name || 'Field',
|
|
8594
|
+
type: 'field',
|
|
8595
|
+
expanded: false,
|
|
8596
|
+
fieldConfig: field,
|
|
8597
|
+
path,
|
|
8598
|
+
children,
|
|
8599
|
+
};
|
|
8600
|
+
}
|
|
8601
|
+
/**
|
|
8602
|
+
* Applies a config patch (label/colSpan only — see field-type-schema.map.ts's
|
|
8603
|
+
* `geographyNode` entry) to one hierarchy level's entry inside a GEOGRAPHY_DYNAMIC field's
|
|
8604
|
+
* nested `geographyConfig.field.nodes[classCode]`, since that's not a real schema array
|
|
8605
|
+
* child that applyFieldPatchToSchema's index-path lookup can reach.
|
|
8606
|
+
*/
|
|
8607
|
+
applyGeographyNodePatchToSchema(path, classCode, patch, originalSchema) {
|
|
8608
|
+
const schema = JSON.parse(JSON.stringify(originalSchema));
|
|
8609
|
+
const field = this.findFieldByPath(schema, path);
|
|
8610
|
+
const nodes = field?.geographyConfig?.field?.nodes;
|
|
8611
|
+
if (nodes && nodes[classCode]) {
|
|
8612
|
+
nodes[classCode] = { ...nodes[classCode], ...patch };
|
|
8613
|
+
}
|
|
8614
|
+
return schema;
|
|
8615
|
+
}
|
|
8460
8616
|
_buildConfiguratorChildNodes(children, basePath) {
|
|
8461
8617
|
const nodes = [];
|
|
8462
8618
|
children.forEach((child, ci) => {
|
|
@@ -8469,12 +8625,12 @@ class FormSchemaTreeService {
|
|
|
8469
8625
|
else if (child.type === 'ROW' && child.children?.length) {
|
|
8470
8626
|
child.children.forEach((rowChild, ri) => {
|
|
8471
8627
|
if (rowChild.isEnabled !== false && rowChild.visible !== false) {
|
|
8472
|
-
nodes.push(this.
|
|
8628
|
+
nodes.push(this._buildConfiguratorLeafNode(rowChild, [...childPath, ri]));
|
|
8473
8629
|
}
|
|
8474
8630
|
});
|
|
8475
8631
|
}
|
|
8476
8632
|
else {
|
|
8477
|
-
nodes.push(this.
|
|
8633
|
+
nodes.push(this._buildConfiguratorLeafNode(child, childPath));
|
|
8478
8634
|
}
|
|
8479
8635
|
});
|
|
8480
8636
|
return nodes;
|
|
@@ -9006,6 +9162,7 @@ class FieldConfiguratorService {
|
|
|
9006
9162
|
_state = signal({
|
|
9007
9163
|
tree: [],
|
|
9008
9164
|
selectedFieldPath: null,
|
|
9165
|
+
selectedGeoClassCode: null,
|
|
9009
9166
|
schema: null,
|
|
9010
9167
|
}, ...(ngDevMode ? [{ debugName: "_state" }] : []));
|
|
9011
9168
|
treeService = new FormSchemaTreeService();
|
|
@@ -9013,11 +9170,33 @@ class FieldConfiguratorService {
|
|
|
9013
9170
|
tree = computed(() => this._state().tree, ...(ngDevMode ? [{ debugName: "tree" }] : []));
|
|
9014
9171
|
schema = computed(() => this._state().schema, ...(ngDevMode ? [{ debugName: "schema" }] : []));
|
|
9015
9172
|
selectedFieldPath = computed(() => this._state().selectedFieldPath, ...(ngDevMode ? [{ debugName: "selectedFieldPath" }] : []));
|
|
9173
|
+
selectedGeoClassCode = computed(() => this._state().selectedGeoClassCode, ...(ngDevMode ? [{ debugName: "selectedGeoClassCode" }] : []));
|
|
9174
|
+
/**
|
|
9175
|
+
* Resolves to the real FieldConfig at the selected path — UNLESS the selection is a
|
|
9176
|
+
* synthetic geography-hierarchy-level node (selectedGeoClassCode set), in which case this
|
|
9177
|
+
* returns a small synthetic FieldConfig built from that level's entry in the parent
|
|
9178
|
+
* GEOGRAPHY_DYNAMIC field's `geographyConfig.field.nodes` map instead. Every downstream
|
|
9179
|
+
* consumer (selectedFieldInfo, selectedFieldBuilderType, the config panel itself) works
|
|
9180
|
+
* against whichever shape comes out of here unchanged — mapFieldTypeToBuilderType('GEOGRAPHY_NODE')
|
|
9181
|
+
* resolves the right minimal config schema (label/colSpan only, see field-type-schema.map.ts).
|
|
9182
|
+
*/
|
|
9016
9183
|
selectedField = computed(() => {
|
|
9017
|
-
const { schema, selectedFieldPath } = this._state();
|
|
9184
|
+
const { schema, selectedFieldPath, selectedGeoClassCode } = this._state();
|
|
9018
9185
|
if (!schema || !selectedFieldPath)
|
|
9019
9186
|
return null;
|
|
9020
|
-
|
|
9187
|
+
const realField = this.treeService.findFieldByPath(schema, selectedFieldPath);
|
|
9188
|
+
if (!realField)
|
|
9189
|
+
return null;
|
|
9190
|
+
if (selectedGeoClassCode) {
|
|
9191
|
+
const nodeCfg = realField.geographyConfig?.field?.nodes?.[selectedGeoClassCode] ?? {};
|
|
9192
|
+
return {
|
|
9193
|
+
name: selectedGeoClassCode,
|
|
9194
|
+
label: nodeCfg.label,
|
|
9195
|
+
colSpan: nodeCfg.colSpan,
|
|
9196
|
+
type: 'GEOGRAPHY_NODE',
|
|
9197
|
+
};
|
|
9198
|
+
}
|
|
9199
|
+
return realField;
|
|
9021
9200
|
}, ...(ngDevMode ? [{ debugName: "selectedField" }] : []));
|
|
9022
9201
|
selectedFieldInfo = computed(() => {
|
|
9023
9202
|
const field = this.selectedField();
|
|
@@ -9056,24 +9235,35 @@ class FieldConfiguratorService {
|
|
|
9056
9235
|
// If preserveSelection is truthy, we definitely keep it.
|
|
9057
9236
|
// Otherwise, we still try to keep it IF the path is still valid in the new schema.
|
|
9058
9237
|
let newPath = s.selectedFieldPath;
|
|
9238
|
+
let newGeoClassCode = s.selectedGeoClassCode;
|
|
9059
9239
|
if (!preserveSelection && newPath) {
|
|
9060
|
-
const
|
|
9061
|
-
if (!
|
|
9240
|
+
const field = this.treeService.findFieldByPath(schema, newPath);
|
|
9241
|
+
if (!field) {
|
|
9062
9242
|
newPath = null;
|
|
9243
|
+
newGeoClassCode = null;
|
|
9244
|
+
}
|
|
9245
|
+
else if (newGeoClassCode && !field.geographyConfig?.field?.nodes?.[newGeoClassCode]) {
|
|
9246
|
+
// The selected hierarchy level no longer exists on this field (e.g. the address
|
|
9247
|
+
// template changed) — fall back to the parent field itself rather than dangling.
|
|
9248
|
+
newGeoClassCode = null;
|
|
9249
|
+
}
|
|
9063
9250
|
}
|
|
9064
9251
|
return {
|
|
9065
9252
|
...s,
|
|
9066
9253
|
tree,
|
|
9067
9254
|
selectedFieldPath: newPath,
|
|
9255
|
+
selectedGeoClassCode: newGeoClassCode,
|
|
9068
9256
|
schema: JSON.parse(JSON.stringify(schema)),
|
|
9069
9257
|
};
|
|
9070
9258
|
});
|
|
9071
9259
|
}
|
|
9072
9260
|
/**
|
|
9073
|
-
* Select a field by its path. Pass null to deselect.
|
|
9261
|
+
* Select a field by its path. Pass null to deselect. `geoClassCode` selects a synthetic
|
|
9262
|
+
* geography-hierarchy-level child of the GEOGRAPHY_DYNAMIC field at `path` instead of the
|
|
9263
|
+
* field itself — see ConfiguratorTreeNode.geoClassCode / selectedField above.
|
|
9074
9264
|
*/
|
|
9075
|
-
selectField(path) {
|
|
9076
|
-
this._state.update(s => ({ ...s, selectedFieldPath: path }));
|
|
9265
|
+
selectField(path, geoClassCode = null) {
|
|
9266
|
+
this._state.update(s => ({ ...s, selectedFieldPath: path, selectedGeoClassCode: geoClassCode }));
|
|
9077
9267
|
}
|
|
9078
9268
|
/**
|
|
9079
9269
|
* Toggle a tree node's expanded state.
|
|
@@ -9089,10 +9279,12 @@ class FieldConfiguratorService {
|
|
|
9089
9279
|
* Rebuilds the schema and tree nodes immutably.
|
|
9090
9280
|
*/
|
|
9091
9281
|
patchSelectedField(patch) {
|
|
9092
|
-
const { schema, selectedFieldPath, tree } = this._state();
|
|
9282
|
+
const { schema, selectedFieldPath, selectedGeoClassCode, tree } = this._state();
|
|
9093
9283
|
if (!schema || !selectedFieldPath)
|
|
9094
9284
|
return;
|
|
9095
|
-
const newSchema =
|
|
9285
|
+
const newSchema = selectedGeoClassCode
|
|
9286
|
+
? this.treeService.applyGeographyNodePatchToSchema(selectedFieldPath, selectedGeoClassCode, patch, schema)
|
|
9287
|
+
: this.treeService.applyFieldPatchToSchema(selectedFieldPath, patch, schema);
|
|
9096
9288
|
// Rebuild the tree to reflect label changes etc.
|
|
9097
9289
|
const newTree = this.treeService.parseSchemaToConfiguratorTree(newSchema);
|
|
9098
9290
|
// Preserve expanded states from the old tree
|
|
@@ -9100,15 +9292,19 @@ class FieldConfiguratorService {
|
|
|
9100
9292
|
this._state.set({
|
|
9101
9293
|
schema: newSchema,
|
|
9102
9294
|
selectedFieldPath,
|
|
9295
|
+
selectedGeoClassCode,
|
|
9103
9296
|
tree: newTree,
|
|
9104
9297
|
});
|
|
9105
9298
|
}
|
|
9106
9299
|
/**
|
|
9107
9300
|
* Change the type (and optionally subType) of the currently selected field.
|
|
9108
9301
|
* Mapping goes from builderType keys (e.g. 'richText') → {type, subType?}.
|
|
9109
|
-
* DROPDOWN fields cannot be changed and are guarded here as well
|
|
9302
|
+
* DROPDOWN fields cannot be changed and are guarded here as well — same for a synthetic
|
|
9303
|
+
* geography-hierarchy-level selection, which has no real `type` to switch at all.
|
|
9110
9304
|
*/
|
|
9111
9305
|
changeFieldType(builderType) {
|
|
9306
|
+
if (this._state().selectedGeoClassCode)
|
|
9307
|
+
return;
|
|
9112
9308
|
const currentField = this.selectedField();
|
|
9113
9309
|
if (!currentField)
|
|
9114
9310
|
return;
|
|
@@ -9516,6 +9712,17 @@ const DEFAULT_FIELD_TYPE_SCHEMA_MAP = {
|
|
|
9516
9712
|
hint: 'Use data.field_name to reference other fields'
|
|
9517
9713
|
},
|
|
9518
9714
|
]), FLAGS_SECTION, ADVANCED_SECTION),
|
|
9715
|
+
// ── GEOGRAPHY (GEOGRAPHY_DYNAMIC → geographyConfig, whole-block settings) ──
|
|
9716
|
+
geography: buildSchema(BASE_SECTION, FLAGS_SECTION, ADVANCED_SECTION),
|
|
9717
|
+
// ── GEOGRAPHY NODE (one hierarchy level of a GEOGRAPHY_DYNAMIC field, e.g. Country/State/
|
|
9718
|
+
// District — a synthetic child, not a real schema field; see
|
|
9719
|
+
// FormSchemaTreeService.applyGeographyNodePatchToSchema). Only label/colSpan are
|
|
9720
|
+
// meaningful per level: mandatoriness is always forced off for every field but Center
|
|
9721
|
+
// Name (see lc-master-form.ts's lockRequiredFields), and name/payloadPath/API config are
|
|
9722
|
+
// all derived from the resolved template, not editable per-level. ─────────────────────
|
|
9723
|
+
geographyNode: buildSchema(section('Basic Settings', [
|
|
9724
|
+
row(F.label, F.colSpan),
|
|
9725
|
+
])),
|
|
9519
9726
|
// ── GROUP & SECTION ───────────────────────────────────────────────────────
|
|
9520
9727
|
group: buildSchema(section('Group Settings', [
|
|
9521
9728
|
row(F.label, F.name),
|
|
@@ -9531,18 +9738,21 @@ const DEFAULT_FIELD_TYPE_SCHEMA_MAP = {
|
|
|
9531
9738
|
class ConfiguratorTreeComponent {
|
|
9532
9739
|
tree = [];
|
|
9533
9740
|
selectedFieldPath = null;
|
|
9741
|
+
/** Distinguishes a GEOGRAPHY_DYNAMIC field itself from one of its synthetic hierarchy-level
|
|
9742
|
+
* children — both share the same `path`, so `path` alone can't tell them apart. */
|
|
9743
|
+
selectedGeoClassCode = null;
|
|
9534
9744
|
selectField = new EventEmitter();
|
|
9535
9745
|
toggleExpanded = new EventEmitter();
|
|
9536
9746
|
onNodeClick(node) {
|
|
9537
9747
|
if (node.type === 'field') {
|
|
9538
|
-
this.selectField.emit(node.path);
|
|
9748
|
+
this.selectField.emit({ path: node.path, geoClassCode: node.geoClassCode });
|
|
9539
9749
|
}
|
|
9540
9750
|
else {
|
|
9541
9751
|
this.toggleExpanded.emit(node.id);
|
|
9542
9752
|
}
|
|
9543
9753
|
}
|
|
9544
9754
|
onFieldSelect(node) {
|
|
9545
|
-
this.selectField.emit(node.path);
|
|
9755
|
+
this.selectField.emit({ path: node.path, geoClassCode: node.geoClassCode });
|
|
9546
9756
|
}
|
|
9547
9757
|
onToggleExpand(node, event) {
|
|
9548
9758
|
event.stopPropagation();
|
|
@@ -9551,7 +9761,9 @@ class ConfiguratorTreeComponent {
|
|
|
9551
9761
|
isSelected(node) {
|
|
9552
9762
|
if (!this.selectedFieldPath || !node.path)
|
|
9553
9763
|
return false;
|
|
9554
|
-
|
|
9764
|
+
if (!this.pathsEqual(node.path, this.selectedFieldPath))
|
|
9765
|
+
return false;
|
|
9766
|
+
return (node.geoClassCode ?? null) === (this.selectedGeoClassCode ?? null);
|
|
9555
9767
|
}
|
|
9556
9768
|
trackByNodeId(_index, node) {
|
|
9557
9769
|
return node.id;
|
|
@@ -9562,15 +9774,17 @@ class ConfiguratorTreeComponent {
|
|
|
9562
9774
|
return a.every((v, i) => v === b[i]);
|
|
9563
9775
|
}
|
|
9564
9776
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfiguratorTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9565
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: ConfiguratorTreeComponent, isStandalone: false, selector: "lib-configurator-tree", inputs: { tree: "tree", selectedFieldPath: "selectedFieldPath" }, outputs: { selectField: "selectField", toggleExpanded: "toggleExpanded" }, ngImport: i0, template: "<div class=\"fb-cfg-tree\">\r\n <div class=\"fb-cfg-tree__header\">\r\n <h4 class=\"fb-cfg-tree__title\">Field Tree</h4>\r\n <p class=\"fb-cfg-tree__subtitle\">Select a field to configure</p>\r\n </div>\r\n\r\n <div class=\"fb-cfg-tree__scrollable\">\r\n @for (node of tree; track trackByNodeId($index, node)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: node, depth: 0 }\"></ng-container>\r\n }\r\n\r\n @if (tree.length === 0) {\r\n <div class=\"fb-cfg-tree__empty\">\r\n No fields to configure.\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n\r\n<!-- Recursive tree node template -->\r\n<ng-template #treeNodeTpl let-node let-depth=\"depth\">\r\n @if (node.type === 'field') {\r\n <!-- Field node (clickable leaf) -->\r\n <div\r\n class=\"fb-cfg-tree-item\"\r\n [class.fb-cfg-tree-item--active]=\"isSelected(node)\"\r\n (click)=\"onFieldSelect(node)\"\r\n [style.padding-left.px]=\"16 + depth * 16\"\r\n >\r\n <span class=\"fb-cfg-tree-item__drag\" title=\"Drag to reorder\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <circle cx=\"9\" cy=\"5\" r=\"1\"/><circle cx=\"9\" cy=\"12\" r=\"1\"/>\r\n <circle cx=\"9\" cy=\"19\" r=\"1\"/><circle cx=\"15\" cy=\"5\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"12\" r=\"1\"/><circle cx=\"15\" cy=\"19\" r=\"1\"/>\r\n </svg>\r\n </span>\r\n <div class=\"fb-cfg-tree-item__content\">\r\n <span class=\"fb-cfg-tree-item__label\">{{ node.label }}</span>\r\n @if (node.fieldConfig?.type) {\r\n <span class=\"fb-cfg-tree-item__type\">{{ node.fieldConfig.type }}</span>\r\n }\r\n </div>\r\n </div>\r\n } @else {\r\n <!-- Group or Section node (expandable) -->\r\n <div\r\n class=\"fb-cfg-tree-section\"\r\n [style.padding-left.px]=\"8 + depth * 12\"\r\n >\r\n <div class=\"fb-cfg-tree-section__header\" (click)=\"onNodeClick(node)\">\r\n <div class=\"fb-cfg-tree-section__title-group\">\r\n <span\r\n class=\"fb-cfg-tree-section__chevron\"\r\n [class.fb-cfg-tree-section__chevron--expanded]=\"node.expanded\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <polyline points=\"9 18 15 12 9 6\"></polyline>\r\n </svg>\r\n </span>\r\n <span class=\"fb-cfg-tree-section__label\">{{ node.label }}</span>\r\n </div>\r\n </div>\r\n\r\n @if (node.expanded && node.children.length > 0) {\r\n <div class=\"fb-cfg-tree-section__children\">\r\n @for (child of node.children; track trackByNodeId($index, child)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: child, depth: depth + 1 }\"></ng-container>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</ng-template>\r\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;height:100%;overflow:hidden}.fb-cfg-tree{display:flex;flex-direction:column;height:100%;overflow:hidden}.fb-cfg-tree__header{padding:16px 20px;border-bottom:1px solid var(--fb-fc-border, #e5e7eb);background:var(--fb-fc-tree-header-bg, #ffffff);flex-shrink:0}@media(max-width:768px){.fb-cfg-tree__header{padding:12px 16px}}@media(max-width:640px){.fb-cfg-tree__header{padding:10px 12px}}.fb-cfg-tree__title{margin:0;font-size:14px;font-weight:700;color:var(--fb-fc-tree-title-color, #111827)}@media(max-width:640px){.fb-cfg-tree__title{font-size:13px}}.fb-cfg-tree__subtitle{margin:4px 0 0;font-size:11px;color:var(--fb-fc-tree-subtitle-color, #6b7280);letter-spacing:.02em}@media(max-width:640px){.fb-cfg-tree__subtitle{font-size:10px}}.fb-cfg-tree__scrollable{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;padding:16px}@media(max-width:768px){.fb-cfg-tree__scrollable{padding:12px}}@media(max-width:640px){.fb-cfg-tree__scrollable{padding:8px}}.fb-cfg-tree__empty{padding:32px 16px;text-align:center;color:var(--fb-fc-empty-color, #9ca3af);font-size:13px}@media(max-width:640px){.fb-cfg-tree__empty{padding:24px 12px;font-size:12px}}.fb-cfg-tree-section{margin-bottom:16px}@media(max-width:768px){.fb-cfg-tree-section{margin-bottom:12px}}@media(max-width:640px){.fb-cfg-tree-section{margin-bottom:8px}}.fb-cfg-tree-section__header{display:flex;align-items:center;justify-content:space-between;padding:4px 8px 8px;border-bottom:1px solid var(--fb-fc-section-divider, #f3f4f6);margin-bottom:8px;cursor:pointer}@media(max-width:640px){.fb-cfg-tree-section__header{padding:3px 6px 6px;margin-bottom:6px}}.fb-cfg-tree-section__header:hover{background:var(--fb-fc-section-hover, #f9fafb);border-radius:6px}.fb-cfg-tree-section__title-group{display:flex;align-items:center;gap:6px}@media(max-width:640px){.fb-cfg-tree-section__title-group{gap:4px}}.fb-cfg-tree-section__chevron{display:flex;color:var(--fb-fc-chevron-color, #9ca3af);transition:transform .2s cubic-bezier(.4,0,.2,1)}.fb-cfg-tree-section__chevron--expanded{transform:rotate(90deg)}.fb-cfg-tree-section__label{font-size:13px;font-weight:700;color:var(--fb-fc-section-label-color, #111827);text-transform:uppercase;letter-spacing:.05em}@media(max-width:640px){.fb-cfg-tree-section__label{font-size:12px;letter-spacing:.02em}}.fb-cfg-tree-section__children{display:flex;flex-direction:column;gap:8px}@media(max-width:640px){.fb-cfg-tree-section__children{gap:6px}}.fb-cfg-tree-item{display:flex;align-items:center;padding:12px;background:var(--fb-fc-item-bg, #ffffff);border:1px solid var(--fb-fc-item-border, #e5e7eb);border-radius:10px;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1)}.fb-cfg-tree-item:hover{border-color:var(--fb-fc-item-hover-border, #3b82f6);box-shadow:0 2px 8px #3b82f614}.fb-cfg-tree-item--active{border-color:var(--fb-fc-item-active-border, #3b82f6);background:var(--fb-fc-item-active-bg, #f0f7ff);box-shadow:0 0 0 1px var(--fb-fc-item-active-border, #3b82f6)}.fb-cfg-tree-item__drag{color:var(--fb-fc-drag-color, #d1d5db);cursor:grab;margin-right:8px;display:flex}.fb-cfg-tree-item__content{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.fb-cfg-tree-item__label{font-size:13px;font-weight:600;color:var(--fb-fc-item-label-color, #111827);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.fb-cfg-tree-item__type{font-size:10px;color:var(--fb-fc-item-type-color, #6b7280);text-transform:uppercase;letter-spacing:.05em;font-weight:500}\n"], dependencies: [{ kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9777
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: ConfiguratorTreeComponent, isStandalone: false, selector: "lib-configurator-tree", inputs: { tree: "tree", selectedFieldPath: "selectedFieldPath", selectedGeoClassCode: "selectedGeoClassCode" }, outputs: { selectField: "selectField", toggleExpanded: "toggleExpanded" }, ngImport: i0, template: "<div class=\"fb-cfg-tree\">\r\n <div class=\"fb-cfg-tree__header\">\r\n <h4 class=\"fb-cfg-tree__title\">Field Tree</h4>\r\n <p class=\"fb-cfg-tree__subtitle\">Select a field to configure</p>\r\n </div>\r\n\r\n <div class=\"fb-cfg-tree__scrollable\">\r\n @for (node of tree; track trackByNodeId($index, node)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: node, depth: 0 }\"></ng-container>\r\n }\r\n\r\n @if (tree.length === 0) {\r\n <div class=\"fb-cfg-tree__empty\">\r\n No fields to configure.\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n\r\n<!-- Recursive tree node template -->\r\n<ng-template #treeNodeTpl let-node let-depth=\"depth\">\r\n @if (node.type === 'field') {\r\n <!-- Field node (clickable leaf) \u2014 may itself have synthetic children (see\r\n geoClassCode), in which case it also gets an expand chevron. -->\r\n <div\r\n class=\"fb-cfg-tree-item\"\r\n [class.fb-cfg-tree-item--active]=\"isSelected(node)\"\r\n (click)=\"onFieldSelect(node)\"\r\n [style.padding-left.px]=\"16 + depth * 16\"\r\n >\r\n @if (node.children.length > 0) {\r\n <span\r\n class=\"fb-cfg-tree-item__chevron\"\r\n [class.fb-cfg-tree-item__chevron--expanded]=\"node.expanded\"\r\n (click)=\"onToggleExpand(node, $event)\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <polyline points=\"9 18 15 12 9 6\"></polyline>\r\n </svg>\r\n </span>\r\n }\r\n <span class=\"fb-cfg-tree-item__drag\" title=\"Drag to reorder\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <circle cx=\"9\" cy=\"5\" r=\"1\"/><circle cx=\"9\" cy=\"12\" r=\"1\"/>\r\n <circle cx=\"9\" cy=\"19\" r=\"1\"/><circle cx=\"15\" cy=\"5\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"12\" r=\"1\"/><circle cx=\"15\" cy=\"19\" r=\"1\"/>\r\n </svg>\r\n </span>\r\n <div class=\"fb-cfg-tree-item__content\">\r\n <span class=\"fb-cfg-tree-item__label\">{{ node.label }}</span>\r\n @if (node.fieldConfig?.type) {\r\n <span class=\"fb-cfg-tree-item__type\">{{ node.fieldConfig.type }}</span>\r\n }\r\n </div>\r\n </div>\r\n @if (node.children.length > 0 && node.expanded) {\r\n <div class=\"fb-cfg-tree-section__children\">\r\n @for (child of node.children; track trackByNodeId($index, child)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: child, depth: depth + 1 }\"></ng-container>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <!-- Group or Section node (expandable) -->\r\n <div\r\n class=\"fb-cfg-tree-section\"\r\n [style.padding-left.px]=\"8 + depth * 12\"\r\n >\r\n <div class=\"fb-cfg-tree-section__header\" (click)=\"onNodeClick(node)\">\r\n <div class=\"fb-cfg-tree-section__title-group\">\r\n <span\r\n class=\"fb-cfg-tree-section__chevron\"\r\n [class.fb-cfg-tree-section__chevron--expanded]=\"node.expanded\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <polyline points=\"9 18 15 12 9 6\"></polyline>\r\n </svg>\r\n </span>\r\n <span class=\"fb-cfg-tree-section__label\">{{ node.label }}</span>\r\n </div>\r\n </div>\r\n\r\n @if (node.expanded && node.children.length > 0) {\r\n <div class=\"fb-cfg-tree-section__children\">\r\n @for (child of node.children; track trackByNodeId($index, child)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: child, depth: depth + 1 }\"></ng-container>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</ng-template>\r\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;height:100%;overflow:hidden}.fb-cfg-tree{display:flex;flex-direction:column;height:100%;overflow:hidden}.fb-cfg-tree__header{padding:16px 20px;border-bottom:1px solid var(--fb-fc-border, #e5e7eb);background:var(--fb-fc-tree-header-bg, #ffffff);flex-shrink:0}@media(max-width:768px){.fb-cfg-tree__header{padding:12px 16px}}@media(max-width:640px){.fb-cfg-tree__header{padding:10px 12px}}.fb-cfg-tree__title{margin:0;font-size:14px;font-weight:700;color:var(--fb-fc-tree-title-color, #111827)}@media(max-width:640px){.fb-cfg-tree__title{font-size:13px}}.fb-cfg-tree__subtitle{margin:4px 0 0;font-size:11px;color:var(--fb-fc-tree-subtitle-color, #6b7280);letter-spacing:.02em}@media(max-width:640px){.fb-cfg-tree__subtitle{font-size:10px}}.fb-cfg-tree__scrollable{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;padding:16px}@media(max-width:768px){.fb-cfg-tree__scrollable{padding:12px}}@media(max-width:640px){.fb-cfg-tree__scrollable{padding:8px}}.fb-cfg-tree__empty{padding:32px 16px;text-align:center;color:var(--fb-fc-empty-color, #9ca3af);font-size:13px}@media(max-width:640px){.fb-cfg-tree__empty{padding:24px 12px;font-size:12px}}.fb-cfg-tree-section{margin-bottom:16px}@media(max-width:768px){.fb-cfg-tree-section{margin-bottom:12px}}@media(max-width:640px){.fb-cfg-tree-section{margin-bottom:8px}}.fb-cfg-tree-section__header{display:flex;align-items:center;justify-content:space-between;padding:4px 8px 8px;border-bottom:1px solid var(--fb-fc-section-divider, #f3f4f6);margin-bottom:8px;cursor:pointer}@media(max-width:640px){.fb-cfg-tree-section__header{padding:3px 6px 6px;margin-bottom:6px}}.fb-cfg-tree-section__header:hover{background:var(--fb-fc-section-hover, #f9fafb);border-radius:6px}.fb-cfg-tree-section__title-group{display:flex;align-items:center;gap:6px}@media(max-width:640px){.fb-cfg-tree-section__title-group{gap:4px}}.fb-cfg-tree-section__chevron{display:flex;color:var(--fb-fc-chevron-color, #9ca3af);transition:transform .2s cubic-bezier(.4,0,.2,1)}.fb-cfg-tree-section__chevron--expanded{transform:rotate(90deg)}.fb-cfg-tree-section__label{font-size:13px;font-weight:700;color:var(--fb-fc-section-label-color, #111827);text-transform:uppercase;letter-spacing:.05em}@media(max-width:640px){.fb-cfg-tree-section__label{font-size:12px;letter-spacing:.02em}}.fb-cfg-tree-section__children{display:flex;flex-direction:column;gap:8px}@media(max-width:640px){.fb-cfg-tree-section__children{gap:6px}}.fb-cfg-tree-item{display:flex;align-items:center;padding:12px;background:var(--fb-fc-item-bg, #ffffff);border:1px solid var(--fb-fc-item-border, #e5e7eb);border-radius:10px;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1)}.fb-cfg-tree-item:hover{border-color:var(--fb-fc-item-hover-border, #3b82f6);box-shadow:0 2px 8px #3b82f614}.fb-cfg-tree-item--active{border-color:var(--fb-fc-item-active-border, #3b82f6);background:var(--fb-fc-item-active-bg, #f0f7ff);box-shadow:0 0 0 1px var(--fb-fc-item-active-border, #3b82f6)}.fb-cfg-tree-item__drag{color:var(--fb-fc-drag-color, #d1d5db);cursor:grab;margin-right:8px;display:flex}.fb-cfg-tree-item__chevron{display:flex;color:var(--fb-fc-chevron-color, #9ca3af);transition:transform .2s cubic-bezier(.4,0,.2,1);margin-right:4px;cursor:pointer}.fb-cfg-tree-item__chevron--expanded{transform:rotate(90deg)}.fb-cfg-tree-item__content{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.fb-cfg-tree-item__label{font-size:13px;font-weight:600;color:var(--fb-fc-item-label-color, #111827);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.fb-cfg-tree-item__type{font-size:10px;color:var(--fb-fc-item-type-color, #6b7280);text-transform:uppercase;letter-spacing:.05em;font-weight:500}\n"], dependencies: [{ kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9566
9778
|
}
|
|
9567
9779
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfiguratorTreeComponent, decorators: [{
|
|
9568
9780
|
type: Component,
|
|
9569
|
-
args: [{ selector: 'lib-configurator-tree', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-cfg-tree\">\r\n <div class=\"fb-cfg-tree__header\">\r\n <h4 class=\"fb-cfg-tree__title\">Field Tree</h4>\r\n <p class=\"fb-cfg-tree__subtitle\">Select a field to configure</p>\r\n </div>\r\n\r\n <div class=\"fb-cfg-tree__scrollable\">\r\n @for (node of tree; track trackByNodeId($index, node)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: node, depth: 0 }\"></ng-container>\r\n }\r\n\r\n @if (tree.length === 0) {\r\n <div class=\"fb-cfg-tree__empty\">\r\n No fields to configure.\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n\r\n<!-- Recursive tree node template -->\r\n<ng-template #treeNodeTpl let-node let-depth=\"depth\">\r\n @if (node.type === 'field') {\r\n <!-- Field node (clickable leaf) -->\r\n <div\r\n class=\"fb-cfg-tree-item\"\r\n [class.fb-cfg-tree-item--active]=\"isSelected(node)\"\r\n (click)=\"onFieldSelect(node)\"\r\n [style.padding-left.px]=\"16 + depth * 16\"\r\n >\r\n <span class=\"fb-cfg-tree-item__drag\" title=\"Drag to reorder\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <circle cx=\"9\" cy=\"5\" r=\"1\"/><circle cx=\"9\" cy=\"12\" r=\"1\"/>\r\n <circle cx=\"9\" cy=\"19\" r=\"1\"/><circle cx=\"15\" cy=\"5\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"12\" r=\"1\"/><circle cx=\"15\" cy=\"19\" r=\"1\"/>\r\n </svg>\r\n </span>\r\n <div class=\"fb-cfg-tree-item__content\">\r\n <span class=\"fb-cfg-tree-item__label\">{{ node.label }}</span>\r\n @if (node.fieldConfig?.type) {\r\n <span class=\"fb-cfg-tree-item__type\">{{ node.fieldConfig.type }}</span>\r\n }\r\n </div>\r\n </div>\r\n } @else {\r\n <!-- Group or Section node (expandable) -->\r\n <div\r\n class=\"fb-cfg-tree-section\"\r\n [style.padding-left.px]=\"8 + depth * 12\"\r\n >\r\n <div class=\"fb-cfg-tree-section__header\" (click)=\"onNodeClick(node)\">\r\n <div class=\"fb-cfg-tree-section__title-group\">\r\n <span\r\n class=\"fb-cfg-tree-section__chevron\"\r\n [class.fb-cfg-tree-section__chevron--expanded]=\"node.expanded\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <polyline points=\"9 18 15 12 9 6\"></polyline>\r\n </svg>\r\n </span>\r\n <span class=\"fb-cfg-tree-section__label\">{{ node.label }}</span>\r\n </div>\r\n </div>\r\n\r\n @if (node.expanded && node.children.length > 0) {\r\n <div class=\"fb-cfg-tree-section__children\">\r\n @for (child of node.children; track trackByNodeId($index, child)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: child, depth: depth + 1 }\"></ng-container>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</ng-template>\r\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;height:100%;overflow:hidden}.fb-cfg-tree{display:flex;flex-direction:column;height:100%;overflow:hidden}.fb-cfg-tree__header{padding:16px 20px;border-bottom:1px solid var(--fb-fc-border, #e5e7eb);background:var(--fb-fc-tree-header-bg, #ffffff);flex-shrink:0}@media(max-width:768px){.fb-cfg-tree__header{padding:12px 16px}}@media(max-width:640px){.fb-cfg-tree__header{padding:10px 12px}}.fb-cfg-tree__title{margin:0;font-size:14px;font-weight:700;color:var(--fb-fc-tree-title-color, #111827)}@media(max-width:640px){.fb-cfg-tree__title{font-size:13px}}.fb-cfg-tree__subtitle{margin:4px 0 0;font-size:11px;color:var(--fb-fc-tree-subtitle-color, #6b7280);letter-spacing:.02em}@media(max-width:640px){.fb-cfg-tree__subtitle{font-size:10px}}.fb-cfg-tree__scrollable{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;padding:16px}@media(max-width:768px){.fb-cfg-tree__scrollable{padding:12px}}@media(max-width:640px){.fb-cfg-tree__scrollable{padding:8px}}.fb-cfg-tree__empty{padding:32px 16px;text-align:center;color:var(--fb-fc-empty-color, #9ca3af);font-size:13px}@media(max-width:640px){.fb-cfg-tree__empty{padding:24px 12px;font-size:12px}}.fb-cfg-tree-section{margin-bottom:16px}@media(max-width:768px){.fb-cfg-tree-section{margin-bottom:12px}}@media(max-width:640px){.fb-cfg-tree-section{margin-bottom:8px}}.fb-cfg-tree-section__header{display:flex;align-items:center;justify-content:space-between;padding:4px 8px 8px;border-bottom:1px solid var(--fb-fc-section-divider, #f3f4f6);margin-bottom:8px;cursor:pointer}@media(max-width:640px){.fb-cfg-tree-section__header{padding:3px 6px 6px;margin-bottom:6px}}.fb-cfg-tree-section__header:hover{background:var(--fb-fc-section-hover, #f9fafb);border-radius:6px}.fb-cfg-tree-section__title-group{display:flex;align-items:center;gap:6px}@media(max-width:640px){.fb-cfg-tree-section__title-group{gap:4px}}.fb-cfg-tree-section__chevron{display:flex;color:var(--fb-fc-chevron-color, #9ca3af);transition:transform .2s cubic-bezier(.4,0,.2,1)}.fb-cfg-tree-section__chevron--expanded{transform:rotate(90deg)}.fb-cfg-tree-section__label{font-size:13px;font-weight:700;color:var(--fb-fc-section-label-color, #111827);text-transform:uppercase;letter-spacing:.05em}@media(max-width:640px){.fb-cfg-tree-section__label{font-size:12px;letter-spacing:.02em}}.fb-cfg-tree-section__children{display:flex;flex-direction:column;gap:8px}@media(max-width:640px){.fb-cfg-tree-section__children{gap:6px}}.fb-cfg-tree-item{display:flex;align-items:center;padding:12px;background:var(--fb-fc-item-bg, #ffffff);border:1px solid var(--fb-fc-item-border, #e5e7eb);border-radius:10px;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1)}.fb-cfg-tree-item:hover{border-color:var(--fb-fc-item-hover-border, #3b82f6);box-shadow:0 2px 8px #3b82f614}.fb-cfg-tree-item--active{border-color:var(--fb-fc-item-active-border, #3b82f6);background:var(--fb-fc-item-active-bg, #f0f7ff);box-shadow:0 0 0 1px var(--fb-fc-item-active-border, #3b82f6)}.fb-cfg-tree-item__drag{color:var(--fb-fc-drag-color, #d1d5db);cursor:grab;margin-right:8px;display:flex}.fb-cfg-tree-item__content{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.fb-cfg-tree-item__label{font-size:13px;font-weight:600;color:var(--fb-fc-item-label-color, #111827);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.fb-cfg-tree-item__type{font-size:10px;color:var(--fb-fc-item-type-color, #6b7280);text-transform:uppercase;letter-spacing:.05em;font-weight:500}\n"] }]
|
|
9781
|
+
args: [{ selector: 'lib-configurator-tree', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-cfg-tree\">\r\n <div class=\"fb-cfg-tree__header\">\r\n <h4 class=\"fb-cfg-tree__title\">Field Tree</h4>\r\n <p class=\"fb-cfg-tree__subtitle\">Select a field to configure</p>\r\n </div>\r\n\r\n <div class=\"fb-cfg-tree__scrollable\">\r\n @for (node of tree; track trackByNodeId($index, node)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: node, depth: 0 }\"></ng-container>\r\n }\r\n\r\n @if (tree.length === 0) {\r\n <div class=\"fb-cfg-tree__empty\">\r\n No fields to configure.\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n\r\n<!-- Recursive tree node template -->\r\n<ng-template #treeNodeTpl let-node let-depth=\"depth\">\r\n @if (node.type === 'field') {\r\n <!-- Field node (clickable leaf) \u2014 may itself have synthetic children (see\r\n geoClassCode), in which case it also gets an expand chevron. -->\r\n <div\r\n class=\"fb-cfg-tree-item\"\r\n [class.fb-cfg-tree-item--active]=\"isSelected(node)\"\r\n (click)=\"onFieldSelect(node)\"\r\n [style.padding-left.px]=\"16 + depth * 16\"\r\n >\r\n @if (node.children.length > 0) {\r\n <span\r\n class=\"fb-cfg-tree-item__chevron\"\r\n [class.fb-cfg-tree-item__chevron--expanded]=\"node.expanded\"\r\n (click)=\"onToggleExpand(node, $event)\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <polyline points=\"9 18 15 12 9 6\"></polyline>\r\n </svg>\r\n </span>\r\n }\r\n <span class=\"fb-cfg-tree-item__drag\" title=\"Drag to reorder\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <circle cx=\"9\" cy=\"5\" r=\"1\"/><circle cx=\"9\" cy=\"12\" r=\"1\"/>\r\n <circle cx=\"9\" cy=\"19\" r=\"1\"/><circle cx=\"15\" cy=\"5\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"12\" r=\"1\"/><circle cx=\"15\" cy=\"19\" r=\"1\"/>\r\n </svg>\r\n </span>\r\n <div class=\"fb-cfg-tree-item__content\">\r\n <span class=\"fb-cfg-tree-item__label\">{{ node.label }}</span>\r\n @if (node.fieldConfig?.type) {\r\n <span class=\"fb-cfg-tree-item__type\">{{ node.fieldConfig.type }}</span>\r\n }\r\n </div>\r\n </div>\r\n @if (node.children.length > 0 && node.expanded) {\r\n <div class=\"fb-cfg-tree-section__children\">\r\n @for (child of node.children; track trackByNodeId($index, child)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: child, depth: depth + 1 }\"></ng-container>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <!-- Group or Section node (expandable) -->\r\n <div\r\n class=\"fb-cfg-tree-section\"\r\n [style.padding-left.px]=\"8 + depth * 12\"\r\n >\r\n <div class=\"fb-cfg-tree-section__header\" (click)=\"onNodeClick(node)\">\r\n <div class=\"fb-cfg-tree-section__title-group\">\r\n <span\r\n class=\"fb-cfg-tree-section__chevron\"\r\n [class.fb-cfg-tree-section__chevron--expanded]=\"node.expanded\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <polyline points=\"9 18 15 12 9 6\"></polyline>\r\n </svg>\r\n </span>\r\n <span class=\"fb-cfg-tree-section__label\">{{ node.label }}</span>\r\n </div>\r\n </div>\r\n\r\n @if (node.expanded && node.children.length > 0) {\r\n <div class=\"fb-cfg-tree-section__children\">\r\n @for (child of node.children; track trackByNodeId($index, child)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: child, depth: depth + 1 }\"></ng-container>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</ng-template>\r\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;height:100%;overflow:hidden}.fb-cfg-tree{display:flex;flex-direction:column;height:100%;overflow:hidden}.fb-cfg-tree__header{padding:16px 20px;border-bottom:1px solid var(--fb-fc-border, #e5e7eb);background:var(--fb-fc-tree-header-bg, #ffffff);flex-shrink:0}@media(max-width:768px){.fb-cfg-tree__header{padding:12px 16px}}@media(max-width:640px){.fb-cfg-tree__header{padding:10px 12px}}.fb-cfg-tree__title{margin:0;font-size:14px;font-weight:700;color:var(--fb-fc-tree-title-color, #111827)}@media(max-width:640px){.fb-cfg-tree__title{font-size:13px}}.fb-cfg-tree__subtitle{margin:4px 0 0;font-size:11px;color:var(--fb-fc-tree-subtitle-color, #6b7280);letter-spacing:.02em}@media(max-width:640px){.fb-cfg-tree__subtitle{font-size:10px}}.fb-cfg-tree__scrollable{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;padding:16px}@media(max-width:768px){.fb-cfg-tree__scrollable{padding:12px}}@media(max-width:640px){.fb-cfg-tree__scrollable{padding:8px}}.fb-cfg-tree__empty{padding:32px 16px;text-align:center;color:var(--fb-fc-empty-color, #9ca3af);font-size:13px}@media(max-width:640px){.fb-cfg-tree__empty{padding:24px 12px;font-size:12px}}.fb-cfg-tree-section{margin-bottom:16px}@media(max-width:768px){.fb-cfg-tree-section{margin-bottom:12px}}@media(max-width:640px){.fb-cfg-tree-section{margin-bottom:8px}}.fb-cfg-tree-section__header{display:flex;align-items:center;justify-content:space-between;padding:4px 8px 8px;border-bottom:1px solid var(--fb-fc-section-divider, #f3f4f6);margin-bottom:8px;cursor:pointer}@media(max-width:640px){.fb-cfg-tree-section__header{padding:3px 6px 6px;margin-bottom:6px}}.fb-cfg-tree-section__header:hover{background:var(--fb-fc-section-hover, #f9fafb);border-radius:6px}.fb-cfg-tree-section__title-group{display:flex;align-items:center;gap:6px}@media(max-width:640px){.fb-cfg-tree-section__title-group{gap:4px}}.fb-cfg-tree-section__chevron{display:flex;color:var(--fb-fc-chevron-color, #9ca3af);transition:transform .2s cubic-bezier(.4,0,.2,1)}.fb-cfg-tree-section__chevron--expanded{transform:rotate(90deg)}.fb-cfg-tree-section__label{font-size:13px;font-weight:700;color:var(--fb-fc-section-label-color, #111827);text-transform:uppercase;letter-spacing:.05em}@media(max-width:640px){.fb-cfg-tree-section__label{font-size:12px;letter-spacing:.02em}}.fb-cfg-tree-section__children{display:flex;flex-direction:column;gap:8px}@media(max-width:640px){.fb-cfg-tree-section__children{gap:6px}}.fb-cfg-tree-item{display:flex;align-items:center;padding:12px;background:var(--fb-fc-item-bg, #ffffff);border:1px solid var(--fb-fc-item-border, #e5e7eb);border-radius:10px;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1)}.fb-cfg-tree-item:hover{border-color:var(--fb-fc-item-hover-border, #3b82f6);box-shadow:0 2px 8px #3b82f614}.fb-cfg-tree-item--active{border-color:var(--fb-fc-item-active-border, #3b82f6);background:var(--fb-fc-item-active-bg, #f0f7ff);box-shadow:0 0 0 1px var(--fb-fc-item-active-border, #3b82f6)}.fb-cfg-tree-item__drag{color:var(--fb-fc-drag-color, #d1d5db);cursor:grab;margin-right:8px;display:flex}.fb-cfg-tree-item__chevron{display:flex;color:var(--fb-fc-chevron-color, #9ca3af);transition:transform .2s cubic-bezier(.4,0,.2,1);margin-right:4px;cursor:pointer}.fb-cfg-tree-item__chevron--expanded{transform:rotate(90deg)}.fb-cfg-tree-item__content{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.fb-cfg-tree-item__label{font-size:13px;font-weight:600;color:var(--fb-fc-item-label-color, #111827);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.fb-cfg-tree-item__type{font-size:10px;color:var(--fb-fc-item-type-color, #6b7280);text-transform:uppercase;letter-spacing:.05em;font-weight:500}\n"] }]
|
|
9570
9782
|
}], propDecorators: { tree: [{
|
|
9571
9783
|
type: Input
|
|
9572
9784
|
}], selectedFieldPath: [{
|
|
9573
9785
|
type: Input
|
|
9786
|
+
}], selectedGeoClassCode: [{
|
|
9787
|
+
type: Input
|
|
9574
9788
|
}], selectField: [{
|
|
9575
9789
|
type: Output
|
|
9576
9790
|
}], toggleExpanded: [{
|
|
@@ -9615,10 +9829,11 @@ class ConfiguratorConfigPanelComponent {
|
|
|
9615
9829
|
currentBuilderType = null;
|
|
9616
9830
|
/** Identity key of the currently rendered field — used to detect real field switches. */
|
|
9617
9831
|
_currentFieldKey = '';
|
|
9618
|
-
/** True when
|
|
9832
|
+
/** True when type switching should be disabled — DROPDOWN-based fields, and synthetic
|
|
9833
|
+
* geography-hierarchy-level nodes (GEOGRAPHY_NODE), which have no real `type` to switch. */
|
|
9619
9834
|
get isDropdownType() {
|
|
9620
9835
|
const t = this.selectedField?.type?.toUpperCase();
|
|
9621
|
-
return t === 'DROPDOWN' || t === 'MULTI_SELECT';
|
|
9836
|
+
return t === 'DROPDOWN' || t === 'MULTI_SELECT' || t === 'GEOGRAPHY_NODE';
|
|
9622
9837
|
}
|
|
9623
9838
|
ngOnChanges(changes) {
|
|
9624
9839
|
if ((changes['selectedField'] || changes['builderFieldType'] || changes['fieldTypeSchemaMap'])
|
|
@@ -10018,8 +10233,8 @@ class FieldConfiguratorComponent {
|
|
|
10018
10233
|
this._isInternalChange = false;
|
|
10019
10234
|
}
|
|
10020
10235
|
}
|
|
10021
|
-
onFieldSelected(
|
|
10022
|
-
this.store.selectField(path);
|
|
10236
|
+
onFieldSelected(selection) {
|
|
10237
|
+
this.store.selectField(selection.path, selection.geoClassCode ?? null);
|
|
10023
10238
|
this.cdr.markForCheck();
|
|
10024
10239
|
}
|
|
10025
10240
|
onNodeToggleExpanded(nodeId) {
|
|
@@ -10043,11 +10258,11 @@ class FieldConfiguratorComponent {
|
|
|
10043
10258
|
}
|
|
10044
10259
|
}
|
|
10045
10260
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FieldConfiguratorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10046
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: FieldConfiguratorComponent, isStandalone: false, selector: "lib-field-configurator", inputs: { schema: "schema", showOptionConfig: "showOptionConfig", lockedFieldNames: "lockedFieldNames" }, outputs: { schemaChange: "schemaChange" }, providers: [FieldConfiguratorService], usesOnChanges: true, ngImport: i0, template: "<div class=\"fb-configurator\">\r\n <div class=\"fb-configurator__layout\">\r\n <div class=\"fb-configurator__sidebar\">\r\n <lib-configurator-tree\r\n [tree]=\"store.tree()\"\r\n [selectedFieldPath]=\"store.selectedFieldPath()\"\r\n (selectField)=\"onFieldSelected($event)\"\r\n (toggleExpanded)=\"onNodeToggleExpanded($event)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-configurator__main\">\r\n <lib-configurator-config-panel\r\n [selectedField]=\"store.selectedField()\"\r\n [selectedFieldInfo]=\"store.selectedFieldInfo()\"\r\n [builderFieldType]=\"store.selectedFieldBuilderType()\"\r\n [fieldTypeSchemaMap]=\"finalFieldTypeSchemaMap\"\r\n [showOptionConfig]=\"showOptionConfig\"\r\n [lockedFieldNames]=\"lockedFieldNames\"\r\n (configChange)=\"onConfigChange($event)\"\r\n (typeChange)=\"onTypeChange($event)\"\r\n />\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".fb-configurator{display:flex;flex-direction:column;height:100%;width:100%;background:var(--fb-fc-bg, #ffffff);font-family:var(--fb-font-family, \"Inter\", sans-serif)}.fb-configurator__layout{flex:1;display:flex;overflow:hidden;width:100%}@media(max-width:768px){.fb-configurator__layout{flex-direction:column}}.fb-configurator__sidebar{flex:0 0 280px;border-right:1px solid var(--fb-fc-border, #e5e7eb);background:var(--fb-fc-sidebar-bg, #f9fafb);display:flex;flex-direction:column;overflow:hidden;min-width:0}@media(max-width:1024px){.fb-configurator__sidebar{flex:0 0 250px}}@media(min-width:1440px){.fb-configurator__sidebar{flex:0 0 300px}}@media(max-width:768px){.fb-configurator__sidebar{flex:0 0 auto;width:100%;border-right:none;border-bottom:1px solid var(--fb-fc-border, #e5e7eb);max-height:40vh}}@media(max-width:640px){.fb-configurator__sidebar{max-height:35vh}}.fb-configurator__main{flex:1;min-width:0;overflow-y:auto;overflow-x:hidden;background:var(--fb-fc-main-bg, #ffffff);display:flex;flex-direction:column}@media(max-width:768px){.fb-configurator__main{width:100%;flex:1;min-height:0}}\n"], dependencies: [{ kind: "component", type: ConfiguratorTreeComponent, selector: "lib-configurator-tree", inputs: ["tree", "selectedFieldPath"], outputs: ["selectField", "toggleExpanded"] }, { kind: "component", type: ConfiguratorConfigPanelComponent, selector: "lib-configurator-config-panel", inputs: ["selectedField", "selectedFieldInfo", "builderFieldType", "fieldTypeSchemaMap", "showOptionConfig", "lockedFieldNames"], outputs: ["configChange", "typeChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
10261
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: FieldConfiguratorComponent, isStandalone: false, selector: "lib-field-configurator", inputs: { schema: "schema", showOptionConfig: "showOptionConfig", lockedFieldNames: "lockedFieldNames" }, outputs: { schemaChange: "schemaChange" }, providers: [FieldConfiguratorService], usesOnChanges: true, ngImport: i0, template: "<div class=\"fb-configurator\">\r\n <div class=\"fb-configurator__layout\">\r\n <div class=\"fb-configurator__sidebar\">\r\n <lib-configurator-tree\r\n [tree]=\"store.tree()\"\r\n [selectedFieldPath]=\"store.selectedFieldPath()\"\r\n [selectedGeoClassCode]=\"store.selectedGeoClassCode()\"\r\n (selectField)=\"onFieldSelected($event)\"\r\n (toggleExpanded)=\"onNodeToggleExpanded($event)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-configurator__main\">\r\n <lib-configurator-config-panel\r\n [selectedField]=\"store.selectedField()\"\r\n [selectedFieldInfo]=\"store.selectedFieldInfo()\"\r\n [builderFieldType]=\"store.selectedFieldBuilderType()\"\r\n [fieldTypeSchemaMap]=\"finalFieldTypeSchemaMap\"\r\n [showOptionConfig]=\"showOptionConfig\"\r\n [lockedFieldNames]=\"lockedFieldNames\"\r\n (configChange)=\"onConfigChange($event)\"\r\n (typeChange)=\"onTypeChange($event)\"\r\n />\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".fb-configurator{display:flex;flex-direction:column;height:100%;width:100%;background:var(--fb-fc-bg, #ffffff);font-family:var(--fb-font-family, \"Inter\", sans-serif)}.fb-configurator__layout{flex:1;display:flex;overflow:hidden;width:100%}@media(max-width:768px){.fb-configurator__layout{flex-direction:column}}.fb-configurator__sidebar{flex:0 0 280px;border-right:1px solid var(--fb-fc-border, #e5e7eb);background:var(--fb-fc-sidebar-bg, #f9fafb);display:flex;flex-direction:column;overflow:hidden;min-width:0}@media(max-width:1024px){.fb-configurator__sidebar{flex:0 0 250px}}@media(min-width:1440px){.fb-configurator__sidebar{flex:0 0 300px}}@media(max-width:768px){.fb-configurator__sidebar{flex:0 0 auto;width:100%;border-right:none;border-bottom:1px solid var(--fb-fc-border, #e5e7eb);max-height:40vh}}@media(max-width:640px){.fb-configurator__sidebar{max-height:35vh}}.fb-configurator__main{flex:1;min-width:0;overflow-y:auto;overflow-x:hidden;background:var(--fb-fc-main-bg, #ffffff);display:flex;flex-direction:column}@media(max-width:768px){.fb-configurator__main{width:100%;flex:1;min-height:0}}\n"], dependencies: [{ kind: "component", type: ConfiguratorTreeComponent, selector: "lib-configurator-tree", inputs: ["tree", "selectedFieldPath", "selectedGeoClassCode"], outputs: ["selectField", "toggleExpanded"] }, { kind: "component", type: ConfiguratorConfigPanelComponent, selector: "lib-configurator-config-panel", inputs: ["selectedField", "selectedFieldInfo", "builderFieldType", "fieldTypeSchemaMap", "showOptionConfig", "lockedFieldNames"], outputs: ["configChange", "typeChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
10047
10262
|
}
|
|
10048
10263
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FieldConfiguratorComponent, decorators: [{
|
|
10049
10264
|
type: Component,
|
|
10050
|
-
args: [{ selector: 'lib-field-configurator', standalone: false, providers: [FieldConfiguratorService], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-configurator\">\r\n <div class=\"fb-configurator__layout\">\r\n <div class=\"fb-configurator__sidebar\">\r\n <lib-configurator-tree\r\n [tree]=\"store.tree()\"\r\n [selectedFieldPath]=\"store.selectedFieldPath()\"\r\n (selectField)=\"onFieldSelected($event)\"\r\n (toggleExpanded)=\"onNodeToggleExpanded($event)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-configurator__main\">\r\n <lib-configurator-config-panel\r\n [selectedField]=\"store.selectedField()\"\r\n [selectedFieldInfo]=\"store.selectedFieldInfo()\"\r\n [builderFieldType]=\"store.selectedFieldBuilderType()\"\r\n [fieldTypeSchemaMap]=\"finalFieldTypeSchemaMap\"\r\n [showOptionConfig]=\"showOptionConfig\"\r\n [lockedFieldNames]=\"lockedFieldNames\"\r\n (configChange)=\"onConfigChange($event)\"\r\n (typeChange)=\"onTypeChange($event)\"\r\n />\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".fb-configurator{display:flex;flex-direction:column;height:100%;width:100%;background:var(--fb-fc-bg, #ffffff);font-family:var(--fb-font-family, \"Inter\", sans-serif)}.fb-configurator__layout{flex:1;display:flex;overflow:hidden;width:100%}@media(max-width:768px){.fb-configurator__layout{flex-direction:column}}.fb-configurator__sidebar{flex:0 0 280px;border-right:1px solid var(--fb-fc-border, #e5e7eb);background:var(--fb-fc-sidebar-bg, #f9fafb);display:flex;flex-direction:column;overflow:hidden;min-width:0}@media(max-width:1024px){.fb-configurator__sidebar{flex:0 0 250px}}@media(min-width:1440px){.fb-configurator__sidebar{flex:0 0 300px}}@media(max-width:768px){.fb-configurator__sidebar{flex:0 0 auto;width:100%;border-right:none;border-bottom:1px solid var(--fb-fc-border, #e5e7eb);max-height:40vh}}@media(max-width:640px){.fb-configurator__sidebar{max-height:35vh}}.fb-configurator__main{flex:1;min-width:0;overflow-y:auto;overflow-x:hidden;background:var(--fb-fc-main-bg, #ffffff);display:flex;flex-direction:column}@media(max-width:768px){.fb-configurator__main{width:100%;flex:1;min-height:0}}\n"] }]
|
|
10265
|
+
args: [{ selector: 'lib-field-configurator', standalone: false, providers: [FieldConfiguratorService], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-configurator\">\r\n <div class=\"fb-configurator__layout\">\r\n <div class=\"fb-configurator__sidebar\">\r\n <lib-configurator-tree\r\n [tree]=\"store.tree()\"\r\n [selectedFieldPath]=\"store.selectedFieldPath()\"\r\n [selectedGeoClassCode]=\"store.selectedGeoClassCode()\"\r\n (selectField)=\"onFieldSelected($event)\"\r\n (toggleExpanded)=\"onNodeToggleExpanded($event)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-configurator__main\">\r\n <lib-configurator-config-panel\r\n [selectedField]=\"store.selectedField()\"\r\n [selectedFieldInfo]=\"store.selectedFieldInfo()\"\r\n [builderFieldType]=\"store.selectedFieldBuilderType()\"\r\n [fieldTypeSchemaMap]=\"finalFieldTypeSchemaMap\"\r\n [showOptionConfig]=\"showOptionConfig\"\r\n [lockedFieldNames]=\"lockedFieldNames\"\r\n (configChange)=\"onConfigChange($event)\"\r\n (typeChange)=\"onTypeChange($event)\"\r\n />\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".fb-configurator{display:flex;flex-direction:column;height:100%;width:100%;background:var(--fb-fc-bg, #ffffff);font-family:var(--fb-font-family, \"Inter\", sans-serif)}.fb-configurator__layout{flex:1;display:flex;overflow:hidden;width:100%}@media(max-width:768px){.fb-configurator__layout{flex-direction:column}}.fb-configurator__sidebar{flex:0 0 280px;border-right:1px solid var(--fb-fc-border, #e5e7eb);background:var(--fb-fc-sidebar-bg, #f9fafb);display:flex;flex-direction:column;overflow:hidden;min-width:0}@media(max-width:1024px){.fb-configurator__sidebar{flex:0 0 250px}}@media(min-width:1440px){.fb-configurator__sidebar{flex:0 0 300px}}@media(max-width:768px){.fb-configurator__sidebar{flex:0 0 auto;width:100%;border-right:none;border-bottom:1px solid var(--fb-fc-border, #e5e7eb);max-height:40vh}}@media(max-width:640px){.fb-configurator__sidebar{max-height:35vh}}.fb-configurator__main{flex:1;min-width:0;overflow-y:auto;overflow-x:hidden;background:var(--fb-fc-main-bg, #ffffff);display:flex;flex-direction:column}@media(max-width:768px){.fb-configurator__main{width:100%;flex:1;min-height:0}}\n"] }]
|
|
10051
10266
|
}], propDecorators: { schema: [{
|
|
10052
10267
|
type: Input,
|
|
10053
10268
|
args: [{ required: true }]
|