@rippling/rippling-sdk 0.2.0-alpha.45 → 0.2.0-alpha.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/manifest/app.d.mts +2 -2
- package/lib/manifest/app.d.mts.map +1 -1
- package/lib/manifest/app.d.ts +2 -2
- package/lib/manifest/app.d.ts.map +1 -1
- package/lib/manifest/app.js +15 -4
- package/lib/manifest/app.js.map +1 -1
- package/lib/manifest/app.mjs +15 -4
- package/lib/manifest/app.mjs.map +1 -1
- package/lib/manifest/custom-object-page-layout.d.mts +8 -3
- package/lib/manifest/custom-object-page-layout.d.mts.map +1 -1
- package/lib/manifest/custom-object-page-layout.d.ts +8 -3
- package/lib/manifest/custom-object-page-layout.d.ts.map +1 -1
- package/lib/manifest/custom-object-page-layout.js +107 -14
- package/lib/manifest/custom-object-page-layout.js.map +1 -1
- package/lib/manifest/custom-object-page-layout.mjs +107 -14
- package/lib/manifest/custom-object-page-layout.mjs.map +1 -1
- package/package.json +1 -1
- package/src/lib/manifest/app.ts +19 -5
- package/src/lib/manifest/custom-object-page-layout.ts +123 -17
- package/src/version.ts +1 -1
- package/version.d.mts +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.mjs +1 -1
package/src/lib/manifest/app.ts
CHANGED
|
@@ -58,9 +58,9 @@ export interface AppProps {
|
|
|
58
58
|
/**
|
|
59
59
|
* SDUI pages shown as tabs in the app. Tab order matches the array order.
|
|
60
60
|
*
|
|
61
|
-
*
|
|
61
|
+
* Required. Must include at least one page.
|
|
62
62
|
*/
|
|
63
|
-
pages
|
|
63
|
+
pages: AppPage[];
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
function resolvePage(entry: AppPage): Record<string, any> {
|
|
@@ -77,6 +77,20 @@ function resolvePage(entry: AppPage): Record<string, any> {
|
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
function resolvePages(pages: AppPage[] | undefined): Record<string, any>[] {
|
|
81
|
+
if (pages == null || pages.length === 0) {
|
|
82
|
+
throw new Error('App pages must include at least one page.');
|
|
83
|
+
}
|
|
84
|
+
return pages.map(resolvePage);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function clonePages(value: unknown): Record<string, any>[] {
|
|
88
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
89
|
+
throw new Error('App pages must include at least one page.');
|
|
90
|
+
}
|
|
91
|
+
return cloneJson(value) as Record<string, any>[];
|
|
92
|
+
}
|
|
93
|
+
|
|
80
94
|
function cloneJson<T>(value: T): T {
|
|
81
95
|
if (value == null) return value;
|
|
82
96
|
return JSON.parse(JSON.stringify(value)) as T;
|
|
@@ -130,7 +144,7 @@ export class App {
|
|
|
130
144
|
this._description = props.description;
|
|
131
145
|
this._appType = props.appType;
|
|
132
146
|
this._icon = props.icon;
|
|
133
|
-
this._pages = (props.pages
|
|
147
|
+
this._pages = resolvePages(props.pages);
|
|
134
148
|
scope._register(this);
|
|
135
149
|
}
|
|
136
150
|
|
|
@@ -150,7 +164,7 @@ export class App {
|
|
|
150
164
|
_description: component['description'],
|
|
151
165
|
_appType: component['app_type'],
|
|
152
166
|
_icon: App.appIconFromExistingComponent(component['icon']),
|
|
153
|
-
_pages:
|
|
167
|
+
_pages: clonePages(component['pages']),
|
|
154
168
|
});
|
|
155
169
|
scope._register(app);
|
|
156
170
|
return app;
|
|
@@ -193,7 +207,7 @@ export class App {
|
|
|
193
207
|
component['icon'] = { s3_bucket: this._icon.s3Bucket, s3_key: this._icon.s3Key };
|
|
194
208
|
}
|
|
195
209
|
if (this._appType != null) component['app_type'] = this._appType;
|
|
196
|
-
|
|
210
|
+
component['pages'] = this._pages.map((p) => ({ ...p }));
|
|
197
211
|
return component;
|
|
198
212
|
}
|
|
199
213
|
}
|
|
@@ -27,7 +27,7 @@ export interface SystemHeaderFieldEdit {
|
|
|
27
27
|
* Custom header field added via `newFields`.
|
|
28
28
|
*
|
|
29
29
|
* `key` is required and must be non-empty — it is used as the stable identity
|
|
30
|
-
* for this field in
|
|
30
|
+
* for this field in visibility conditions.
|
|
31
31
|
*/
|
|
32
32
|
export interface NewHeaderField {
|
|
33
33
|
/** RQL field name to display. Required. */
|
|
@@ -64,7 +64,7 @@ export interface HeaderEdits {
|
|
|
64
64
|
systemFieldEdits?: Record<string, SystemHeaderFieldEdit>;
|
|
65
65
|
/** Additional custom fields to add to the header. Optional. */
|
|
66
66
|
newFields?: NewHeaderField[];
|
|
67
|
-
/** Ordered list of header field
|
|
67
|
+
/** Ordered list of header field RQL names. Custom header keys are accepted and converted. Optional. */
|
|
68
68
|
headerFieldsOrder?: string[];
|
|
69
69
|
/** Action button keys to show in the header. Optional. */
|
|
70
70
|
buttons?: string[];
|
|
@@ -351,7 +351,7 @@ export interface RemoveSystemPageLayoutSectionOptions {
|
|
|
351
351
|
|
|
352
352
|
/** Options for adding a tab to a layout. */
|
|
353
353
|
export interface AddPageLayoutTabOptions {
|
|
354
|
-
/** Insert position inside `newTabs`. Optional. @default `'end'` */
|
|
354
|
+
/** Insert position inside `newTabs` and `tabsOrder`. Optional. @default `'end'` */
|
|
355
355
|
position?: PageLayoutMutationPosition;
|
|
356
356
|
/** Allow another tab with the same key. Optional. @default false */
|
|
357
357
|
allowDuplicate?: boolean;
|
|
@@ -754,7 +754,49 @@ function normalizeHeaderEdits(headerEdits: HeaderEdits): HeaderEdits {
|
|
|
754
754
|
);
|
|
755
755
|
}
|
|
756
756
|
|
|
757
|
-
return headerEdits;
|
|
757
|
+
if (headerEdits.headerFieldsOrder == null) return headerEdits;
|
|
758
|
+
return {
|
|
759
|
+
...headerEdits,
|
|
760
|
+
headerFieldsOrder: normalizeHeaderFieldsOrder(headerEdits),
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
function addUniqueHeaderOrderField(order: string[], field: unknown): void {
|
|
765
|
+
if (typeof field !== 'string' || field.length === 0) return;
|
|
766
|
+
if (!order.includes(field)) order.push(field);
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
function normalizeHeaderFieldsOrder(headerEdits: HeaderEdits): string[] {
|
|
770
|
+
const customFieldRqlByKey = new Map(
|
|
771
|
+
(headerEdits.newFields ?? []).map((field) => [field.key, field.rqlName]),
|
|
772
|
+
);
|
|
773
|
+
const systemFieldRqlByKey = new Map(
|
|
774
|
+
Object.entries(headerEdits.systemFieldEdits ?? {})
|
|
775
|
+
.filter((entry): entry is [string, SystemHeaderFieldEdit & { newRqlField: string }] => {
|
|
776
|
+
const [, edit] = entry;
|
|
777
|
+
return typeof edit.newRqlField === 'string' && edit.newRqlField.length > 0;
|
|
778
|
+
})
|
|
779
|
+
.map(([key, edit]) => [key, edit.newRqlField]),
|
|
780
|
+
);
|
|
781
|
+
const order: string[] = [];
|
|
782
|
+
|
|
783
|
+
for (const entry of headerEdits.headerFieldsOrder ?? []) {
|
|
784
|
+
addUniqueHeaderOrderField(
|
|
785
|
+
order,
|
|
786
|
+
customFieldRqlByKey.get(entry) ?? systemFieldRqlByKey.get(entry) ?? entry,
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
addUniqueHeaderOrderField(order, headerEdits.newTitleField);
|
|
791
|
+
addUniqueHeaderOrderField(order, headerEdits.newDescriptionField);
|
|
792
|
+
for (const field of headerEdits.newFields ?? []) {
|
|
793
|
+
addUniqueHeaderOrderField(order, field.rqlName);
|
|
794
|
+
}
|
|
795
|
+
for (const systemEdit of Object.values(headerEdits.systemFieldEdits ?? {})) {
|
|
796
|
+
addUniqueHeaderOrderField(order, systemEdit.newRqlField);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
return order;
|
|
758
800
|
}
|
|
759
801
|
|
|
760
802
|
type MutableSectionField = SerializedSectionField | Record<string, any> | string;
|
|
@@ -784,6 +826,15 @@ function insertAt<T>(items: T[], item: T, position: PageLayoutMutationPosition |
|
|
|
784
826
|
items.splice(insertionIndex(items.length, position), 0, item);
|
|
785
827
|
}
|
|
786
828
|
|
|
829
|
+
function insertUniqueAt(
|
|
830
|
+
items: string[],
|
|
831
|
+
item: string | null | undefined,
|
|
832
|
+
position: PageLayoutMutationPosition | undefined,
|
|
833
|
+
): void {
|
|
834
|
+
if (item == null || item.length === 0 || items.includes(item)) return;
|
|
835
|
+
insertAt(items, item, position);
|
|
836
|
+
}
|
|
837
|
+
|
|
787
838
|
function fieldRqlNameOf(entry: unknown): string | undefined {
|
|
788
839
|
if (typeof entry === 'string') return entry;
|
|
789
840
|
if (entry == null || typeof entry !== 'object') return undefined;
|
|
@@ -1231,7 +1282,9 @@ export class CustomObjectPageLayout {
|
|
|
1231
1282
|
options.tabKey,
|
|
1232
1283
|
options.allowDuplicate,
|
|
1233
1284
|
);
|
|
1285
|
+
const sectionsOrder = this.ensureSystemSectionsOrder(tabEdit);
|
|
1234
1286
|
insertAt(sections, normalized, options.position);
|
|
1287
|
+
insertUniqueAt(sectionsOrder, layoutSectionKey(normalized), options.position);
|
|
1235
1288
|
return this;
|
|
1236
1289
|
}
|
|
1237
1290
|
|
|
@@ -1275,6 +1328,7 @@ export class CustomObjectPageLayout {
|
|
|
1275
1328
|
}
|
|
1276
1329
|
const sectionEdit = this.ensureSystemSectionEdit(options.tabKey, sectionOrKey);
|
|
1277
1330
|
sectionEdit.deleted = true;
|
|
1331
|
+
removeKeyFromOrder(this._tabEdits.systemTabEdits?.[options.tabKey]?.sectionsOrder, sectionOrKey);
|
|
1278
1332
|
this.removeSectionVisibility(sectionOrKey);
|
|
1279
1333
|
return this;
|
|
1280
1334
|
}
|
|
@@ -1338,10 +1392,9 @@ export class CustomObjectPageLayout {
|
|
|
1338
1392
|
if (options.allowDuplicate !== true && newTabs.some((existing) => existing.key === normalized.key)) {
|
|
1339
1393
|
throw new Error(`CustomObjectPageLayout already contains tab "${normalized.key}".`);
|
|
1340
1394
|
}
|
|
1395
|
+
const tabsOrder = this.ensureTabsOrder();
|
|
1341
1396
|
insertAt(newTabs, normalized, options.position);
|
|
1342
|
-
|
|
1343
|
-
insertAt(this._tabEdits.tabsOrder, normalized.key, options.position);
|
|
1344
|
-
}
|
|
1397
|
+
insertUniqueAt(tabsOrder, normalized.key, options.position);
|
|
1345
1398
|
return this;
|
|
1346
1399
|
}
|
|
1347
1400
|
|
|
@@ -1381,10 +1434,9 @@ export class CustomObjectPageLayout {
|
|
|
1381
1434
|
if (options.allowDuplicate !== true && newFields.some((existing) => existing.key === headerField.key)) {
|
|
1382
1435
|
throw new Error(`CustomObjectPageLayout header already contains field key "${headerField.key}".`);
|
|
1383
1436
|
}
|
|
1437
|
+
const headerFieldsOrder = this.ensureHeaderFieldsOrder();
|
|
1384
1438
|
insertAt(newFields, headerField, options.position);
|
|
1385
|
-
|
|
1386
|
-
insertAt(this._headerEdits.headerFieldsOrder, headerField.key, options.position);
|
|
1387
|
-
}
|
|
1439
|
+
insertUniqueAt(headerFieldsOrder, headerField.rqlName, options.position);
|
|
1388
1440
|
return this;
|
|
1389
1441
|
}
|
|
1390
1442
|
|
|
@@ -1394,12 +1446,12 @@ export class CustomObjectPageLayout {
|
|
|
1394
1446
|
if (isField(fieldOrKey)) this.assertFieldBelongsToLayout(fieldOrKey);
|
|
1395
1447
|
const key = typeof fieldOrKey === 'string' ? fieldOrKey : fieldApiName;
|
|
1396
1448
|
const newFields = this._headerEdits.newFields ?? [];
|
|
1397
|
-
const
|
|
1449
|
+
const removedFields: NewHeaderField[] = [];
|
|
1398
1450
|
const removed = removeFromArray(
|
|
1399
1451
|
newFields,
|
|
1400
1452
|
(field) => {
|
|
1401
1453
|
const matched = field.key === key || (fieldApiName != null && field.rqlName === fieldApiName);
|
|
1402
|
-
if (matched)
|
|
1454
|
+
if (matched) removedFields.push(field);
|
|
1403
1455
|
return matched;
|
|
1404
1456
|
},
|
|
1405
1457
|
`CustomObjectPageLayout header field "${key}"`,
|
|
@@ -1408,40 +1460,94 @@ export class CustomObjectPageLayout {
|
|
|
1408
1460
|
if (removed === 0) {
|
|
1409
1461
|
throw new Error(`CustomObjectPageLayout header does not contain field "${key}".`);
|
|
1410
1462
|
}
|
|
1411
|
-
for (const
|
|
1412
|
-
removeKeyFromOrder(this._headerEdits.headerFieldsOrder, removedKey);
|
|
1413
|
-
}
|
|
1463
|
+
for (const removedField of removedFields) this.removeHeaderOrderFieldIfUnused(removedField);
|
|
1414
1464
|
return this;
|
|
1415
1465
|
}
|
|
1416
1466
|
|
|
1417
1467
|
/** Sets the record title field in `header_edits`. */
|
|
1418
1468
|
setTitleField(field: Field | string | null): this {
|
|
1419
|
-
this._headerEdits.newTitleField
|
|
1469
|
+
const previousTitleField = this._headerEdits.newTitleField;
|
|
1470
|
+
const nextTitleField = this.headerFieldApiName(field);
|
|
1471
|
+
this._headerEdits.newTitleField = nextTitleField;
|
|
1420
1472
|
if (field != null) this._headerEdits.titleFieldDeleted = false;
|
|
1473
|
+
insertUniqueAt(this.ensureHeaderFieldsOrder(), nextTitleField, 'end');
|
|
1474
|
+
this.removeHeaderOrderFieldIfUnused(previousTitleField);
|
|
1421
1475
|
return this;
|
|
1422
1476
|
}
|
|
1423
1477
|
|
|
1424
1478
|
/** Removes the record title field from the header. */
|
|
1425
1479
|
removeTitleField(): this {
|
|
1480
|
+
const previousTitleField = this._headerEdits.newTitleField;
|
|
1426
1481
|
this._headerEdits.newTitleField = null;
|
|
1427
1482
|
this._headerEdits.titleFieldDeleted = true;
|
|
1483
|
+
this.removeHeaderOrderFieldIfUnused(previousTitleField);
|
|
1428
1484
|
return this;
|
|
1429
1485
|
}
|
|
1430
1486
|
|
|
1431
1487
|
/** Sets the record description field in `header_edits`. */
|
|
1432
1488
|
setDescriptionField(field: Field | string | null): this {
|
|
1433
|
-
this._headerEdits.newDescriptionField
|
|
1489
|
+
const previousDescriptionField = this._headerEdits.newDescriptionField;
|
|
1490
|
+
const nextDescriptionField = this.headerFieldApiName(field);
|
|
1491
|
+
this._headerEdits.newDescriptionField = nextDescriptionField;
|
|
1434
1492
|
if (field != null) this._headerEdits.descriptionFieldDeleted = false;
|
|
1493
|
+
insertUniqueAt(this.ensureHeaderFieldsOrder(), nextDescriptionField, 'end');
|
|
1494
|
+
this.removeHeaderOrderFieldIfUnused(previousDescriptionField);
|
|
1435
1495
|
return this;
|
|
1436
1496
|
}
|
|
1437
1497
|
|
|
1438
1498
|
/** Removes the record description field from the header. */
|
|
1439
1499
|
removeDescriptionField(): this {
|
|
1500
|
+
const previousDescriptionField = this._headerEdits.newDescriptionField;
|
|
1440
1501
|
this._headerEdits.newDescriptionField = null;
|
|
1441
1502
|
this._headerEdits.descriptionFieldDeleted = true;
|
|
1503
|
+
this.removeHeaderOrderFieldIfUnused(previousDescriptionField);
|
|
1442
1504
|
return this;
|
|
1443
1505
|
}
|
|
1444
1506
|
|
|
1507
|
+
private ensureTabsOrder(): string[] {
|
|
1508
|
+
const order = (this._tabEdits.tabsOrder ??= []);
|
|
1509
|
+
for (const tab of this._tabEdits.newTabs ?? []) insertUniqueAt(order, tab.key, 'end');
|
|
1510
|
+
for (const [tabKey, tabEdit] of Object.entries(this._tabEdits.systemTabEdits ?? {})) {
|
|
1511
|
+
if (tabEdit.deleted !== true) insertUniqueAt(order, tabKey, 'end');
|
|
1512
|
+
}
|
|
1513
|
+
return order;
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
private ensureSystemSectionsOrder(tabEdit: SerializedSystemTabEdit): string[] {
|
|
1517
|
+
const order = (tabEdit.sectionsOrder ??= []);
|
|
1518
|
+
for (const section of tabEdit.newSections ?? []) insertUniqueAt(order, layoutSectionKey(section), 'end');
|
|
1519
|
+
for (const [sectionKey, sectionEdit] of Object.entries(tabEdit.systemSectionEdits ?? {})) {
|
|
1520
|
+
if (sectionEdit.deleted !== true) insertUniqueAt(order, sectionKey, 'end');
|
|
1521
|
+
}
|
|
1522
|
+
return order;
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
private ensureHeaderFieldsOrder(): string[] {
|
|
1526
|
+
this._headerEdits.headerFieldsOrder = normalizeHeaderFieldsOrder({
|
|
1527
|
+
...this._headerEdits,
|
|
1528
|
+
headerFieldsOrder: this._headerEdits.headerFieldsOrder ?? [],
|
|
1529
|
+
});
|
|
1530
|
+
return this._headerEdits.headerFieldsOrder;
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
private headerOrderFieldIsUsed(rqlName: string): boolean {
|
|
1534
|
+
return (
|
|
1535
|
+
this._headerEdits.newTitleField === rqlName ||
|
|
1536
|
+
this._headerEdits.newDescriptionField === rqlName ||
|
|
1537
|
+
(this._headerEdits.newFields ?? []).some((field) => field.rqlName === rqlName) ||
|
|
1538
|
+
Object.values(this._headerEdits.systemFieldEdits ?? {}).some((edit) => edit.newRqlField === rqlName)
|
|
1539
|
+
);
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
private removeHeaderOrderFieldIfUnused(field: NewHeaderField | string | null | undefined): void {
|
|
1543
|
+
const rqlName = typeof field === 'string' ? field : field?.rqlName;
|
|
1544
|
+
if (field != null && typeof field !== 'string' && field.key !== rqlName) {
|
|
1545
|
+
removeKeyFromOrder(this._headerEdits.headerFieldsOrder, field.key);
|
|
1546
|
+
}
|
|
1547
|
+
if (rqlName == null || this.headerOrderFieldIsUsed(rqlName)) return;
|
|
1548
|
+
removeKeyFromOrder(this._headerEdits.headerFieldsOrder, rqlName);
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1445
1551
|
private serializeFieldForMutation(
|
|
1446
1552
|
field: Field,
|
|
1447
1553
|
fallbackSectionKey: string,
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.2.0-alpha.
|
|
1
|
+
export const VERSION = '0.2.0-alpha.46'; // x-release-please-version
|
package/version.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.2.0-alpha.
|
|
1
|
+
export declare const VERSION = "0.2.0-alpha.46";
|
|
2
2
|
//# sourceMappingURL=version.d.mts.map
|
package/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.2.0-alpha.
|
|
1
|
+
export declare const VERSION = "0.2.0-alpha.46";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/version.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.VERSION = void 0;
|
|
4
|
-
exports.VERSION = '0.2.0-alpha.
|
|
4
|
+
exports.VERSION = '0.2.0-alpha.46'; // x-release-please-version
|
|
5
5
|
//# sourceMappingURL=version.js.map
|
package/version.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = '0.2.0-alpha.
|
|
1
|
+
export const VERSION = '0.2.0-alpha.46'; // x-release-please-version
|
|
2
2
|
//# sourceMappingURL=version.mjs.map
|