@rippling/rippling-sdk 0.2.0-alpha.37 → 0.2.0-alpha.39
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/examples/sdui/sdui-crud-todo/sdui-crud-todo.ts +3 -3
- package/examples/sdui/sdui-showcase/sdui-showcase.ts +6 -11
- package/examples/sdui/sdui-tab-multi-view/sdui-tab-multi-view.ts +14 -24
- package/examples/sdui/vote/vote.ts +7 -11
- package/lib/manifest/app.d.mts +11 -1
- package/lib/manifest/app.d.mts.map +1 -1
- package/lib/manifest/app.d.ts +11 -1
- package/lib/manifest/app.d.ts.map +1 -1
- package/lib/manifest/app.js +42 -1
- package/lib/manifest/app.js.map +1 -1
- package/lib/manifest/app.mjs +42 -1
- package/lib/manifest/app.mjs.map +1 -1
- package/lib/manifest/category.d.mts +14 -3
- package/lib/manifest/category.d.mts.map +1 -1
- package/lib/manifest/category.d.ts +14 -3
- package/lib/manifest/category.d.ts.map +1 -1
- package/lib/manifest/category.js +25 -3
- package/lib/manifest/category.js.map +1 -1
- package/lib/manifest/category.mjs +25 -3
- package/lib/manifest/category.mjs.map +1 -1
- package/lib/manifest/custom-object-field-section.d.mts +13 -0
- package/lib/manifest/custom-object-field-section.d.mts.map +1 -1
- package/lib/manifest/custom-object-field-section.d.ts +13 -0
- package/lib/manifest/custom-object-field-section.d.ts.map +1 -1
- package/lib/manifest/custom-object-field-section.js +22 -1
- package/lib/manifest/custom-object-field-section.js.map +1 -1
- package/lib/manifest/custom-object-field-section.mjs +22 -1
- package/lib/manifest/custom-object-field-section.mjs.map +1 -1
- package/lib/manifest/custom-object-page-layout.d.mts +23 -0
- package/lib/manifest/custom-object-page-layout.d.mts.map +1 -1
- package/lib/manifest/custom-object-page-layout.d.ts +23 -0
- package/lib/manifest/custom-object-page-layout.d.ts.map +1 -1
- package/lib/manifest/custom-object-page-layout.js +45 -2
- package/lib/manifest/custom-object-page-layout.js.map +1 -1
- package/lib/manifest/custom-object-page-layout.mjs +45 -2
- package/lib/manifest/custom-object-page-layout.mjs.map +1 -1
- package/lib/manifest/custom-object.d.mts +41 -2
- package/lib/manifest/custom-object.d.mts.map +1 -1
- package/lib/manifest/custom-object.d.ts +41 -2
- package/lib/manifest/custom-object.d.ts.map +1 -1
- package/lib/manifest/custom-object.js +70 -3
- package/lib/manifest/custom-object.js.map +1 -1
- package/lib/manifest/custom-object.mjs +70 -3
- package/lib/manifest/custom-object.mjs.map +1 -1
- package/lib/manifest/existing-manifest-context.d.mts +87 -0
- package/lib/manifest/existing-manifest-context.d.mts.map +1 -0
- package/lib/manifest/existing-manifest-context.d.ts +87 -0
- package/lib/manifest/existing-manifest-context.d.ts.map +1 -0
- package/lib/manifest/existing-manifest-context.js +511 -0
- package/lib/manifest/existing-manifest-context.js.map +1 -0
- package/lib/manifest/existing-manifest-context.mjs +506 -0
- package/lib/manifest/existing-manifest-context.mjs.map +1 -0
- package/lib/manifest/field.d.mts +44 -2
- package/lib/manifest/field.d.mts.map +1 -1
- package/lib/manifest/field.d.ts +44 -2
- package/lib/manifest/field.d.ts.map +1 -1
- package/lib/manifest/field.js +134 -3
- package/lib/manifest/field.js.map +1 -1
- package/lib/manifest/field.mjs +134 -3
- package/lib/manifest/field.mjs.map +1 -1
- package/lib/manifest/index.d.mts +8 -7
- package/lib/manifest/index.d.mts.map +1 -1
- package/lib/manifest/index.d.ts +8 -7
- package/lib/manifest/index.d.ts.map +1 -1
- package/lib/manifest/index.js +3 -1
- package/lib/manifest/index.js.map +1 -1
- package/lib/manifest/index.mjs +5 -4
- package/lib/manifest/index.mjs.map +1 -1
- package/lib/manifest/list-view.d.mts +17 -0
- package/lib/manifest/list-view.d.mts.map +1 -1
- package/lib/manifest/list-view.d.ts +17 -0
- package/lib/manifest/list-view.d.ts.map +1 -1
- package/lib/manifest/list-view.js +38 -1
- package/lib/manifest/list-view.js.map +1 -1
- package/lib/manifest/list-view.mjs +38 -1
- package/lib/manifest/list-view.mjs.map +1 -1
- package/lib/manifest/manifest-builder.d.mts +60 -7
- package/lib/manifest/manifest-builder.d.mts.map +1 -1
- package/lib/manifest/manifest-builder.d.ts +60 -7
- package/lib/manifest/manifest-builder.d.ts.map +1 -1
- package/lib/manifest/manifest-builder.js +62 -4
- package/lib/manifest/manifest-builder.js.map +1 -1
- package/lib/manifest/manifest-builder.mjs +62 -4
- package/lib/manifest/manifest-builder.mjs.map +1 -1
- package/lib/manifest/manifest-function.d.mts +18 -3
- package/lib/manifest/manifest-function.d.mts.map +1 -1
- package/lib/manifest/manifest-function.d.ts +18 -3
- package/lib/manifest/manifest-function.d.ts.map +1 -1
- package/lib/manifest/manifest-function.js +44 -3
- package/lib/manifest/manifest-function.js.map +1 -1
- package/lib/manifest/manifest-function.mjs +44 -3
- package/lib/manifest/manifest-function.mjs.map +1 -1
- package/lib/manifest/rule.d.mts +17 -0
- package/lib/manifest/rule.d.mts.map +1 -1
- package/lib/manifest/rule.d.ts +17 -0
- package/lib/manifest/rule.d.ts.map +1 -1
- package/lib/manifest/rule.js +45 -1
- package/lib/manifest/rule.js.map +1 -1
- package/lib/manifest/rule.mjs +45 -1
- package/lib/manifest/rule.mjs.map +1 -1
- package/lib/manifest/sdui-page.d.mts +10 -1
- package/lib/manifest/sdui-page.d.mts.map +1 -1
- package/lib/manifest/sdui-page.d.ts +10 -1
- package/lib/manifest/sdui-page.d.ts.map +1 -1
- package/lib/manifest/sdui-page.js +28 -1
- package/lib/manifest/sdui-page.js.map +1 -1
- package/lib/manifest/sdui-page.mjs +28 -1
- package/lib/manifest/sdui-page.mjs.map +1 -1
- package/lib/manifest/validation.d.mts +17 -0
- package/lib/manifest/validation.d.mts.map +1 -1
- package/lib/manifest/validation.d.ts +17 -0
- package/lib/manifest/validation.d.ts.map +1 -1
- package/lib/manifest/validation.js +31 -1
- package/lib/manifest/validation.js.map +1 -1
- package/lib/manifest/validation.mjs +31 -1
- package/lib/manifest/validation.mjs.map +1 -1
- package/lib/sdui/actions.d.mts.map +1 -1
- package/lib/sdui/actions.d.ts.map +1 -1
- package/lib/sdui/actions.js +23 -13
- package/lib/sdui/actions.js.map +1 -1
- package/lib/sdui/actions.mjs +23 -13
- package/lib/sdui/actions.mjs.map +1 -1
- package/lib/sdui/component.d.mts +28 -11
- package/lib/sdui/component.d.mts.map +1 -1
- package/lib/sdui/component.d.ts +28 -11
- package/lib/sdui/component.d.ts.map +1 -1
- package/lib/sdui/component.js +69 -36
- package/lib/sdui/component.js.map +1 -1
- package/lib/sdui/component.mjs +69 -36
- package/lib/sdui/component.mjs.map +1 -1
- package/lib/sdui/components.d.mts +1141 -132
- package/lib/sdui/components.d.mts.map +1 -1
- package/lib/sdui/components.d.ts +1141 -132
- package/lib/sdui/components.d.ts.map +1 -1
- package/lib/sdui/components.js +834 -206
- package/lib/sdui/components.js.map +1 -1
- package/lib/sdui/components.mjs +830 -203
- package/lib/sdui/components.mjs.map +1 -1
- package/lib/sdui/directives.d.mts.map +1 -1
- package/lib/sdui/directives.d.ts.map +1 -1
- package/lib/sdui/directives.js +4 -1
- package/lib/sdui/directives.js.map +1 -1
- package/lib/sdui/directives.mjs +4 -1
- package/lib/sdui/directives.mjs.map +1 -1
- package/lib/sdui/index.d.mts +314 -261
- package/lib/sdui/index.d.mts.map +1 -1
- package/lib/sdui/index.d.ts +314 -261
- package/lib/sdui/index.d.ts.map +1 -1
- package/lib/sdui/index.js +255 -204
- package/lib/sdui/index.js.map +1 -1
- package/lib/sdui/index.mjs +128 -103
- package/lib/sdui/index.mjs.map +1 -1
- package/lib/sdui/propTypes.d.mts +6330 -0
- package/lib/sdui/propTypes.d.mts.map +1 -0
- package/lib/sdui/propTypes.d.ts +6330 -0
- package/lib/sdui/propTypes.d.ts.map +1 -0
- package/lib/sdui/propTypes.js +14 -0
- package/lib/sdui/propTypes.js.map +1 -0
- package/lib/sdui/propTypes.mjs +13 -0
- package/lib/sdui/propTypes.mjs.map +1 -0
- package/lib/sdui/render.d.mts +1 -1
- package/lib/sdui/render.d.mts.map +1 -1
- package/lib/sdui/render.d.ts +1 -1
- package/lib/sdui/render.d.ts.map +1 -1
- package/lib/sdui/render.js +11 -3
- package/lib/sdui/render.js.map +1 -1
- package/lib/sdui/render.mjs +11 -3
- package/lib/sdui/render.mjs.map +1 -1
- package/lib/sdui/state.d.mts.map +1 -1
- package/lib/sdui/state.d.ts.map +1 -1
- package/lib/sdui/state.js +3 -1
- package/lib/sdui/state.js.map +1 -1
- package/lib/sdui/state.mjs +3 -1
- package/lib/sdui/state.mjs.map +1 -1
- package/package.json +1 -1
- package/src/lib/manifest/app.ts +46 -2
- package/src/lib/manifest/category.ts +35 -7
- package/src/lib/manifest/custom-object-field-section.ts +37 -1
- package/src/lib/manifest/custom-object-page-layout.ts +67 -2
- package/src/lib/manifest/custom-object.ts +88 -4
- package/src/lib/manifest/existing-manifest-context.ts +673 -0
- package/src/lib/manifest/field.ts +160 -3
- package/src/lib/manifest/index.ts +39 -4
- package/src/lib/manifest/list-view.ts +50 -1
- package/src/lib/manifest/manifest-builder.ts +115 -5
- package/src/lib/manifest/manifest-function.ts +44 -4
- package/src/lib/manifest/rule.ts +60 -1
- package/src/lib/manifest/sdui-page.ts +37 -2
- package/src/lib/manifest/validation.ts +48 -1
- package/src/lib/sdui/actions.ts +23 -10
- package/src/lib/sdui/component.ts +84 -44
- package/src/lib/sdui/components.ts +1627 -212
- package/src/lib/sdui/directives.ts +4 -1
- package/src/lib/sdui/index.ts +565 -200
- package/src/lib/sdui/propTypes.ts +8470 -0
- package/src/lib/sdui/render.ts +13 -5
- package/src/lib/sdui/state.ts +8 -2
- 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
|
@@ -7,6 +7,13 @@ import {
|
|
|
7
7
|
} from './_helpers';
|
|
8
8
|
import type { CustomObject } from './custom-object';
|
|
9
9
|
import type { CustomObjectFieldSection } from './custom-object-field-section';
|
|
10
|
+
import { getExistingManifestContext, type ExistingManifestContextOptions } from './existing-manifest-context';
|
|
11
|
+
import type { ManifestComponentDeletion } from './manifest-builder';
|
|
12
|
+
|
|
13
|
+
export interface CustomObjectFieldDeletionIdentifier {
|
|
14
|
+
customObjectApiName: string;
|
|
15
|
+
fieldApiName: string;
|
|
16
|
+
}
|
|
10
17
|
|
|
11
18
|
/**
|
|
12
19
|
* A filter condition applied to a {@link SummaryField}.
|
|
@@ -53,6 +60,11 @@ function validateApiName(apiName: string): void {
|
|
|
53
60
|
}
|
|
54
61
|
}
|
|
55
62
|
|
|
63
|
+
function cloneJson<T>(value: T): T {
|
|
64
|
+
if (value == null) return value;
|
|
65
|
+
return JSON.parse(JSON.stringify(value)) as T;
|
|
66
|
+
}
|
|
67
|
+
|
|
56
68
|
/** Props shared by every field variant. */
|
|
57
69
|
interface CommonFieldProps {
|
|
58
70
|
apiName: string;
|
|
@@ -90,6 +102,61 @@ export interface FieldProps {
|
|
|
90
102
|
summarySpec?: SummarySpec | undefined;
|
|
91
103
|
}
|
|
92
104
|
|
|
105
|
+
export interface FieldLoadFromExistingOptions extends ExistingManifestContextOptions {
|
|
106
|
+
customObjectApiName?: string;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
class ExistingFieldReference {
|
|
110
|
+
private _section: string | null;
|
|
111
|
+
|
|
112
|
+
constructor(
|
|
113
|
+
private readonly customObjectApiName: string,
|
|
114
|
+
private readonly component: Record<string, any>,
|
|
115
|
+
) {
|
|
116
|
+
this._section = (component['section'] as string | null | undefined) ?? null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
getApiName(): string {
|
|
120
|
+
return this.component['field_api_name'];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
getDisplayName(): string {
|
|
124
|
+
return this.component['field_display_name'] ?? this.getApiName();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
getCustomObjectApiName(): string {
|
|
128
|
+
return this.customObjectApiName;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
getFieldType(): FieldType | null {
|
|
132
|
+
return (this.getDataType()['field_type'] as FieldType | undefined) ?? null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
getDataType(): Readonly<Record<string, any>> {
|
|
136
|
+
return this.component['data_type'] ?? {};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
isFormula(): boolean {
|
|
140
|
+
return this.component['derived_field_formula'] != null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
isSummary(): boolean {
|
|
144
|
+
return this.component['derived_aggregated_field'] != null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
getSectionId(): string | null {
|
|
148
|
+
return this._section;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
_assignSection(section: CustomObjectFieldSection | string): void {
|
|
152
|
+
this._section = typeof section === 'string' ? section : section.getSectionId();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
toDict(): Record<string, any> {
|
|
156
|
+
return cloneJson(this.component);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
93
160
|
// ────────────────────────────────────────────────────────────────────────
|
|
94
161
|
// Base class
|
|
95
162
|
// ────────────────────────────────────────────────────────────────────────
|
|
@@ -119,6 +186,16 @@ export interface FieldProps {
|
|
|
119
186
|
* @see {@link TextField}, {@link NumberField}, {@link LookupField}, {@link SummaryField}
|
|
120
187
|
*/
|
|
121
188
|
export class Field {
|
|
189
|
+
static readonly componentType = 'CUSTOM_OBJECT_FIELD' as const;
|
|
190
|
+
|
|
191
|
+
static toDeletionIdentifier(identifier: CustomObjectFieldDeletionIdentifier): ManifestComponentDeletion {
|
|
192
|
+
return {
|
|
193
|
+
type: Field.componentType,
|
|
194
|
+
custom_object_api_name: identifier.customObjectApiName,
|
|
195
|
+
field_api_name: identifier.fieldApiName,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
122
199
|
private readonly _fieldApiName: string;
|
|
123
200
|
private readonly _fieldDisplayName: string;
|
|
124
201
|
private readonly _customObjectApiName: string;
|
|
@@ -172,6 +249,68 @@ export class Field {
|
|
|
172
249
|
customObject._register(this);
|
|
173
250
|
}
|
|
174
251
|
|
|
252
|
+
/**
|
|
253
|
+
* Loads this field from the active existing-manifest JSON context.
|
|
254
|
+
*
|
|
255
|
+
* For fields whose api_name is not globally unique, pass `customObjectApiName`
|
|
256
|
+
* or use a qualified id like `'object__c.field__c'`.
|
|
257
|
+
*/
|
|
258
|
+
static loadFromExisting(apiName: string, options: FieldLoadFromExistingOptions = {}): Field {
|
|
259
|
+
return getExistingManifestContext(options).loadField(apiName, options);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** @internal Hydrates a custom object field from existing manifest wire JSON. */
|
|
263
|
+
static _fromExistingComponent(customObject: CustomObject, component: Record<string, any>): Field {
|
|
264
|
+
const props: FieldProps = {
|
|
265
|
+
apiName: component['field_api_name'],
|
|
266
|
+
displayName: component['field_display_name'] ?? component['field_api_name'],
|
|
267
|
+
};
|
|
268
|
+
if (component['data_type'] !== undefined) props.dataType = cloneJson(component['data_type'] ?? {});
|
|
269
|
+
if (component['description'] !== undefined) props.description = component['description'];
|
|
270
|
+
if (component['is_required'] !== undefined) props.required = component['is_required'];
|
|
271
|
+
if (component['is_unique'] !== undefined) props.unique = component['is_unique'];
|
|
272
|
+
if (component['is_indexed'] !== undefined) props.indexed = component['is_indexed'];
|
|
273
|
+
if (component['rql_formula'] !== undefined) props.rqlFormula = component['rql_formula'];
|
|
274
|
+
if (component['formula_attr_metas'] !== undefined)
|
|
275
|
+
props.formulaAttrMetas = component['formula_attr_metas'];
|
|
276
|
+
if (component['derived_aggregated_field'] !== undefined) {
|
|
277
|
+
props.derivedAggregatedField = component['derived_aggregated_field'];
|
|
278
|
+
}
|
|
279
|
+
if (component['derived_field_formula'] !== undefined)
|
|
280
|
+
props.derivedFieldFormula = component['derived_field_formula'];
|
|
281
|
+
if (component['section'] !== undefined) props.section = component['section'];
|
|
282
|
+
return new Field(customObject, props);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/** @internal Creates a non-registered reference for standard or external fields. */
|
|
286
|
+
static _referenceFromExistingComponent(component: Record<string, any>): Field {
|
|
287
|
+
return new ExistingFieldReference(
|
|
288
|
+
component['custom_object_api_name'],
|
|
289
|
+
cloneJson(component),
|
|
290
|
+
) as unknown as Field;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** @internal Creates a non-registered reference for a known wire field name. */
|
|
294
|
+
static _syntheticReference(customObjectApiName: string, fieldApiName: string): Field {
|
|
295
|
+
return new ExistingFieldReference(customObjectApiName, {
|
|
296
|
+
type: 'CUSTOM_OBJECT_FIELD',
|
|
297
|
+
custom_object_api_name: customObjectApiName,
|
|
298
|
+
field_api_name: fieldApiName,
|
|
299
|
+
field_display_name: fieldApiName,
|
|
300
|
+
data_type: {},
|
|
301
|
+
description: null,
|
|
302
|
+
is_required: null,
|
|
303
|
+
is_unique: null,
|
|
304
|
+
is_indexed: null,
|
|
305
|
+
rql_formula: null,
|
|
306
|
+
formula_attr_metas: null,
|
|
307
|
+
is_standard: true,
|
|
308
|
+
derived_aggregated_field: null,
|
|
309
|
+
derived_field_formula: null,
|
|
310
|
+
section: null,
|
|
311
|
+
}) as unknown as Field;
|
|
312
|
+
}
|
|
313
|
+
|
|
175
314
|
// ── Getters ────────────────────────────────────────────────────────────
|
|
176
315
|
|
|
177
316
|
/** Returns the api_name of this field (e.g. `'first_name__c'`). */
|
|
@@ -220,7 +359,7 @@ export class Field {
|
|
|
220
359
|
*/
|
|
221
360
|
toDict(): Record<string, any> {
|
|
222
361
|
return {
|
|
223
|
-
type:
|
|
362
|
+
type: Field.componentType,
|
|
224
363
|
custom_object_api_name: this._customObjectApiName,
|
|
225
364
|
field_api_name: this._fieldApiName,
|
|
226
365
|
field_display_name: this._fieldDisplayName,
|
|
@@ -446,7 +585,12 @@ export interface SelectFieldProps extends CommonFieldProps {
|
|
|
446
585
|
/** Whether a value is required on save. Optional. */
|
|
447
586
|
required?: boolean;
|
|
448
587
|
}
|
|
449
|
-
/**
|
|
588
|
+
/**
|
|
589
|
+
* Multi-select dropdown field. Renders as a dropdown that allows multiple
|
|
590
|
+
* options to be selected at once.
|
|
591
|
+
*
|
|
592
|
+
* Use {@link RadioField} instead when only one option should be selectable.
|
|
593
|
+
*/
|
|
450
594
|
export class SelectField extends Field {
|
|
451
595
|
constructor(customObject: CustomObject, props: SelectFieldProps) {
|
|
452
596
|
super(customObject, { ...props, fieldType: 'SELECT' });
|
|
@@ -464,7 +608,11 @@ export interface RadioFieldProps extends CommonFieldProps {
|
|
|
464
608
|
/** Whether a value is required on save. Optional. */
|
|
465
609
|
required?: boolean;
|
|
466
610
|
}
|
|
467
|
-
/**
|
|
611
|
+
/**
|
|
612
|
+
* Single-select radio button group field. Exactly one option can be selected.
|
|
613
|
+
*
|
|
614
|
+
* Use {@link SelectField} instead when multiple options should be selectable.
|
|
615
|
+
*/
|
|
468
616
|
export class RadioField extends Field {
|
|
469
617
|
constructor(customObject: CustomObject, props: RadioFieldProps) {
|
|
470
618
|
super(customObject, { ...props, fieldType: 'RADIO' });
|
|
@@ -538,6 +686,15 @@ export interface LookupFieldProps extends CommonFieldProps {
|
|
|
538
686
|
*
|
|
539
687
|
* Use {@link ParentChildField} instead when the relationship should create a
|
|
540
688
|
* parent-child hierarchy with rollup support.
|
|
689
|
+
*
|
|
690
|
+
* @remarks
|
|
691
|
+
* **For "the employee responsible for this record" semantics, consider the built-in
|
|
692
|
+
* `owner_role` standard field instead of a new `LookupField` to `'role'`.** Every
|
|
693
|
+
* `CustomObject` ships with `owner_role` (an Employee reference) plus `created_by`
|
|
694
|
+
* and `last_modified_by`. `owner_role` drives Rippling's record-level permissions,
|
|
695
|
+
* so a parallel custom employee field can fragment ownership and complicate the
|
|
696
|
+
* permission story. Consider a new `LookupField` to `'role'` when you need a
|
|
697
|
+
* *second*, non-owner employee reference (e.g. an "approver", a "manager on record").
|
|
541
698
|
*/
|
|
542
699
|
export class LookupField extends Field {
|
|
543
700
|
constructor(customObject: CustomObject, props: LookupFieldProps) {
|
|
@@ -23,15 +23,21 @@ export { Category, type CategoryProps } from './category';
|
|
|
23
23
|
|
|
24
24
|
export { CustomObject, type CustomObjectProps, type IconConfig } from './custom-object';
|
|
25
25
|
|
|
26
|
-
export {
|
|
26
|
+
export {
|
|
27
|
+
CustomObjectFieldSection,
|
|
28
|
+
type CustomObjectFieldSectionLoadFromExistingOptions,
|
|
29
|
+
type CustomObjectFieldSectionProps,
|
|
30
|
+
} from './custom-object-field-section';
|
|
27
31
|
|
|
28
32
|
export {
|
|
29
33
|
CustomObjectPageLayout,
|
|
34
|
+
type CustomObjectPageLayoutLoadFromExistingOptions,
|
|
30
35
|
type CustomObjectPageLayoutProps,
|
|
31
36
|
type CustomTab,
|
|
32
37
|
type FieldsSection,
|
|
33
38
|
type HeaderEdits,
|
|
34
39
|
type NewHeaderField,
|
|
40
|
+
type PageLayoutDeletionIdentifier,
|
|
35
41
|
type PageLayoutSection,
|
|
36
42
|
type PageLayoutTab,
|
|
37
43
|
type SectionField,
|
|
@@ -49,6 +55,8 @@ export {
|
|
|
49
55
|
|
|
50
56
|
export {
|
|
51
57
|
Field,
|
|
58
|
+
type CustomObjectFieldDeletionIdentifier,
|
|
59
|
+
type FieldLoadFromExistingOptions,
|
|
52
60
|
type FieldProps,
|
|
53
61
|
type SummaryFilter,
|
|
54
62
|
|
|
@@ -94,12 +102,28 @@ export {
|
|
|
94
102
|
type SummaryFieldProps,
|
|
95
103
|
} from './field';
|
|
96
104
|
|
|
97
|
-
export {
|
|
105
|
+
export {
|
|
106
|
+
ExistingManifestContext,
|
|
107
|
+
type ExistingManifest,
|
|
108
|
+
type ExistingManifestContextOptions,
|
|
109
|
+
type ExistingManifestSource,
|
|
110
|
+
} from './existing-manifest-context';
|
|
111
|
+
|
|
112
|
+
export {
|
|
113
|
+
ListViewDef,
|
|
114
|
+
type ListViewDefLoadFromExistingOptions,
|
|
115
|
+
type ListViewDefProps,
|
|
116
|
+
type ListViewDeletionIdentifier,
|
|
117
|
+
} from './list-view';
|
|
98
118
|
|
|
99
119
|
export {
|
|
100
120
|
ManifestBuilder,
|
|
121
|
+
type BuiltManifest,
|
|
101
122
|
type ManifestBuilderProps,
|
|
102
123
|
type ManifestComponent,
|
|
124
|
+
type ManifestComponentClass,
|
|
125
|
+
type ManifestComponentDeletion,
|
|
126
|
+
type ManifestComponentType,
|
|
103
127
|
type ManifestScope,
|
|
104
128
|
} from './manifest-builder';
|
|
105
129
|
|
|
@@ -109,8 +133,19 @@ export {
|
|
|
109
133
|
type ManifestFunctionProps,
|
|
110
134
|
} from './manifest-function';
|
|
111
135
|
|
|
112
|
-
export {
|
|
136
|
+
export {
|
|
137
|
+
Rule,
|
|
138
|
+
type RuleAction,
|
|
139
|
+
type RuleDeletionIdentifier,
|
|
140
|
+
type RuleLoadFromExistingOptions,
|
|
141
|
+
type RuleProps,
|
|
142
|
+
} from './rule';
|
|
113
143
|
|
|
114
144
|
export { SduiPage, type SduiPageProps } from './sdui-page';
|
|
115
145
|
|
|
116
|
-
export {
|
|
146
|
+
export {
|
|
147
|
+
Validation,
|
|
148
|
+
type ValidationDeletionIdentifier,
|
|
149
|
+
type ValidationLoadFromExistingOptions,
|
|
150
|
+
type ValidationProps,
|
|
151
|
+
} from './validation';
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { generateId, type ObjectScope, type SortOrder } from './_helpers';
|
|
2
2
|
import type { CustomObject } from './custom-object';
|
|
3
|
+
import { getExistingManifestContext, type ExistingManifestContextOptions } from './existing-manifest-context';
|
|
3
4
|
import type { Field } from './field';
|
|
5
|
+
import type { ManifestComponentDeletion } from './manifest-builder';
|
|
6
|
+
|
|
7
|
+
export interface ListViewDeletionIdentifier {
|
|
8
|
+
viewId: string;
|
|
9
|
+
objectRqlName: string;
|
|
10
|
+
}
|
|
4
11
|
|
|
5
12
|
/**
|
|
6
13
|
* Initialization properties for {@link ListViewDef}.
|
|
@@ -70,6 +77,10 @@ export interface ListViewDefProps {
|
|
|
70
77
|
rqlFilter?: string;
|
|
71
78
|
}
|
|
72
79
|
|
|
80
|
+
export interface ListViewDefLoadFromExistingOptions extends ExistingManifestContextOptions {
|
|
81
|
+
customObjectApiName?: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
73
84
|
/**
|
|
74
85
|
* Defines a list view and registers it with the manifest.
|
|
75
86
|
*
|
|
@@ -104,6 +115,16 @@ export interface ListViewDefProps {
|
|
|
104
115
|
* ```
|
|
105
116
|
*/
|
|
106
117
|
export class ListViewDef {
|
|
118
|
+
static readonly componentType = 'CUSTOM_OBJECT_LIST_VIEW' as const;
|
|
119
|
+
|
|
120
|
+
static toDeletionIdentifier(identifier: ListViewDeletionIdentifier): ManifestComponentDeletion {
|
|
121
|
+
return {
|
|
122
|
+
type: ListViewDef.componentType,
|
|
123
|
+
view_id: identifier.viewId,
|
|
124
|
+
object_rql_name: identifier.objectRqlName,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
107
128
|
private readonly _viewId: string;
|
|
108
129
|
private readonly _customObjectApiName: string;
|
|
109
130
|
private readonly _name: string;
|
|
@@ -143,6 +164,34 @@ export class ListViewDef {
|
|
|
143
164
|
customObject._register(this);
|
|
144
165
|
}
|
|
145
166
|
|
|
167
|
+
/**
|
|
168
|
+
* Loads this list view from the active existing-manifest JSON context.
|
|
169
|
+
*/
|
|
170
|
+
static loadFromExisting(viewId: string, options: ListViewDefLoadFromExistingOptions = {}): ListViewDef {
|
|
171
|
+
return getExistingManifestContext(options).loadListView(viewId, options);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** @internal Hydrates a list view from existing manifest wire JSON. */
|
|
175
|
+
static _fromExistingComponent(
|
|
176
|
+
customObject: CustomObject,
|
|
177
|
+
component: Record<string, any>,
|
|
178
|
+
resolveField: (apiName: string) => Field,
|
|
179
|
+
): ListViewDef {
|
|
180
|
+
const props: ListViewDefProps = {
|
|
181
|
+
viewId: component['view_id'],
|
|
182
|
+
name: component['name'] ?? component['view_id'],
|
|
183
|
+
fields: (component['fields'] ?? []).map((fieldApiName: string) => resolveField(fieldApiName)),
|
|
184
|
+
isPublic: Boolean(component['public']),
|
|
185
|
+
};
|
|
186
|
+
if (component['description'] !== undefined) props.description = component['description'];
|
|
187
|
+
if (component['object_scope'] !== undefined) props.objectScope = component['object_scope'];
|
|
188
|
+
if (component['sort_order'] !== undefined) props.sortOrder = component['sort_order'];
|
|
189
|
+
if (component['column_config'] !== undefined) props.columnConfig = component['column_config'];
|
|
190
|
+
if (component['rql_filter'] !== undefined) props.rqlFilter = component['rql_filter'];
|
|
191
|
+
if (component['order_by'] != null) props.orderBy = resolveField(component['order_by']);
|
|
192
|
+
return new ListViewDef(customObject, props);
|
|
193
|
+
}
|
|
194
|
+
|
|
146
195
|
/**
|
|
147
196
|
* Returns the stable identifier for this view (e.g. `'view_gym_all_members'`).
|
|
148
197
|
*/
|
|
@@ -165,7 +214,7 @@ export class ListViewDef {
|
|
|
165
214
|
*/
|
|
166
215
|
toDict(): Record<string, any> {
|
|
167
216
|
const d: Record<string, any> = {
|
|
168
|
-
type:
|
|
217
|
+
type: ListViewDef.componentType,
|
|
169
218
|
object_rql_name: this._customObjectApiName,
|
|
170
219
|
view_id: this._viewId,
|
|
171
220
|
name: this._name,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ExistingManifestContext, type ExistingManifestSource } from './existing-manifest-context';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Any object that can be included in a manifest.
|
|
3
5
|
*
|
|
@@ -8,6 +10,39 @@ export interface ManifestComponent {
|
|
|
8
10
|
toDict(): Record<string, any>;
|
|
9
11
|
}
|
|
10
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Wire-level component types supported by the manifest builder.
|
|
15
|
+
*/
|
|
16
|
+
export type ManifestComponentType =
|
|
17
|
+
| 'CUSTOM_APP'
|
|
18
|
+
| 'CUSTOM_CATEGORY'
|
|
19
|
+
| 'CUSTOM_OBJECT'
|
|
20
|
+
| 'CUSTOM_OBJECT_FIELD'
|
|
21
|
+
| 'CUSTOM_OBJECT_FIELD_SECTION'
|
|
22
|
+
| 'CUSTOM_OBJECT_LIST_VIEW'
|
|
23
|
+
| 'CUSTOM_OBJECT_PAGE_LAYOUT'
|
|
24
|
+
| 'CUSTOM_OBJECT_RECORD_TRIGGERED_FLOW'
|
|
25
|
+
| 'CUSTOM_OBJECT_VALIDATION_RULE'
|
|
26
|
+
| 'FUNCTION'
|
|
27
|
+
| 'SDUI_PAGE';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Static side of a manifest component class.
|
|
31
|
+
*/
|
|
32
|
+
export interface ManifestComponentClass<TIdentifierInput = unknown> {
|
|
33
|
+
readonly componentType: ManifestComponentType;
|
|
34
|
+
toDeletionIdentifier(identifier: TIdentifierInput): ManifestComponentDeletion;
|
|
35
|
+
new (...args: any[]): ManifestComponent;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* A manifest component reference that should be deleted during install.
|
|
40
|
+
*/
|
|
41
|
+
export interface ManifestComponentDeletion extends Record<string, any> {
|
|
42
|
+
/** Wire-level component type, e.g. `'CUSTOM_OBJECT'` or `'CUSTOM_OBJECT_FIELD'`. */
|
|
43
|
+
type: ManifestComponentType;
|
|
44
|
+
}
|
|
45
|
+
|
|
11
46
|
/**
|
|
12
47
|
* A scope — anything that can accept child component registrations.
|
|
13
48
|
*
|
|
@@ -44,6 +79,15 @@ export interface ManifestBuilderProps {
|
|
|
44
79
|
description?: string;
|
|
45
80
|
}
|
|
46
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Plain object returned by {@link ManifestBuilder.buildManifest}.
|
|
84
|
+
*/
|
|
85
|
+
export interface BuiltManifest {
|
|
86
|
+
metadata: Record<string, any>;
|
|
87
|
+
components: Record<string, any>[];
|
|
88
|
+
components_to_delete?: ManifestComponentDeletion[];
|
|
89
|
+
}
|
|
90
|
+
|
|
47
91
|
/**
|
|
48
92
|
* Root container for a manifest — collects all components and serializes them to JSON.
|
|
49
93
|
*
|
|
@@ -63,7 +107,7 @@ export interface ManifestBuilderProps {
|
|
|
63
107
|
* description: 'Members, trainers, schedules, and check-in',
|
|
64
108
|
* });
|
|
65
109
|
*
|
|
66
|
-
* const category = new Category(manifest, { apiName: 'gym__c', name: 'Gym' });
|
|
110
|
+
* const category = new Category(manifest, { apiName: 'gym__c', name: 'Gym', description: 'Gym domain' });
|
|
67
111
|
* const memberObj = new CustomObject(manifest, { apiName: 'gym_member__c', name: 'Member', category });
|
|
68
112
|
* // ... define fields, rules, list views, etc. ...
|
|
69
113
|
*
|
|
@@ -75,6 +119,7 @@ export class ManifestBuilder implements ManifestScope {
|
|
|
75
119
|
readonly name: string;
|
|
76
120
|
readonly description: string;
|
|
77
121
|
private readonly _components: ManifestComponent[] = [];
|
|
122
|
+
private readonly _componentsToDelete: ManifestComponentDeletion[] = [];
|
|
78
123
|
|
|
79
124
|
/**
|
|
80
125
|
* @param props - Initialization properties.
|
|
@@ -89,6 +134,24 @@ export class ManifestBuilder implements ManifestScope {
|
|
|
89
134
|
this.description = props.description ?? '';
|
|
90
135
|
}
|
|
91
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Parses an existing manifest JSON blob, installs it as the active load context,
|
|
139
|
+
* hydrates every known component, and returns a normal `ManifestBuilder`.
|
|
140
|
+
*/
|
|
141
|
+
static loadFromExistingJson(source: ExistingManifestSource): ManifestBuilder {
|
|
142
|
+
return ExistingManifestContext.fromJson(source).loadManifestBuilder();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Parses an existing manifest JSON blob and installs it as the active lazy-load context.
|
|
147
|
+
*
|
|
148
|
+
* After calling this, individual components can be loaded with
|
|
149
|
+
* `CustomObjectPageLayout.loadFromExisting(...)`, `Field.loadFromExisting(...)`, etc.
|
|
150
|
+
*/
|
|
151
|
+
static useExistingJson(source: ExistingManifestSource): ExistingManifestContext {
|
|
152
|
+
return ExistingManifestContext.fromJson(source);
|
|
153
|
+
}
|
|
154
|
+
|
|
92
155
|
/**
|
|
93
156
|
* @internal Scope hook invoked by child constructors. Components enter the
|
|
94
157
|
* manifest here — there is no other path.
|
|
@@ -101,11 +164,45 @@ export class ManifestBuilder implements ManifestScope {
|
|
|
101
164
|
}
|
|
102
165
|
|
|
103
166
|
/**
|
|
104
|
-
*
|
|
167
|
+
* Marks a component to be deleted when this manifest is installed.
|
|
105
168
|
*
|
|
106
|
-
* @
|
|
169
|
+
* @param componentClass - Component class, e.g. `CustomObject`.
|
|
170
|
+
* @param identifier - Component identifier/key, such as an api_name or the component's identifier object.
|
|
171
|
+
* @returns This builder for chaining.
|
|
107
172
|
*/
|
|
108
|
-
|
|
173
|
+
markComponentForDeletion<TIdentifierInput>(
|
|
174
|
+
componentClass: ManifestComponentClass<TIdentifierInput>,
|
|
175
|
+
identifier: TIdentifierInput,
|
|
176
|
+
): this {
|
|
177
|
+
if (identifier == null || identifier === '') {
|
|
178
|
+
throw new Error('identifier is required');
|
|
179
|
+
}
|
|
180
|
+
if (!componentClass.componentType) {
|
|
181
|
+
throw new Error('type is required');
|
|
182
|
+
}
|
|
183
|
+
if (typeof componentClass.toDeletionIdentifier !== 'function') {
|
|
184
|
+
throw new TypeError('Component class must have a toDeletionIdentifier() method');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const deletion = componentClass.toDeletionIdentifier(identifier);
|
|
188
|
+
if (!deletion.type) {
|
|
189
|
+
throw new Error('type is required');
|
|
190
|
+
}
|
|
191
|
+
if (Object.keys(deletion).length <= 1) {
|
|
192
|
+
throw new Error('identifier is required');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
this._componentsToDelete.push({ ...deletion });
|
|
196
|
+
return this;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Returns the manifest as a plain object with `metadata`, a flat `components` array,
|
|
201
|
+
* and a `components_to_delete` array when deletions are registered.
|
|
202
|
+
*
|
|
203
|
+
* @returns `{ metadata: { key, name, description? }, components, components_to_delete? }`
|
|
204
|
+
*/
|
|
205
|
+
buildManifest(): BuiltManifest {
|
|
109
206
|
const metadata: Record<string, any> = {
|
|
110
207
|
key: this.key,
|
|
111
208
|
name: this.name,
|
|
@@ -114,7 +211,11 @@ export class ManifestBuilder implements ManifestScope {
|
|
|
114
211
|
metadata['description'] = this.description;
|
|
115
212
|
}
|
|
116
213
|
const components = this._components.map((c) => c.toDict());
|
|
117
|
-
|
|
214
|
+
const manifest: BuiltManifest = { metadata, components };
|
|
215
|
+
if (this._componentsToDelete.length > 0) {
|
|
216
|
+
manifest.components_to_delete = this.componentsToDeleteList();
|
|
217
|
+
}
|
|
218
|
+
return manifest;
|
|
118
219
|
}
|
|
119
220
|
|
|
120
221
|
/**
|
|
@@ -126,6 +227,15 @@ export class ManifestBuilder implements ManifestScope {
|
|
|
126
227
|
return this._components.map((c) => c.toDict());
|
|
127
228
|
}
|
|
128
229
|
|
|
230
|
+
/**
|
|
231
|
+
* Returns the flat list of component deletion references.
|
|
232
|
+
*
|
|
233
|
+
* @returns An array of component identifier objects, in registration order.
|
|
234
|
+
*/
|
|
235
|
+
componentsToDeleteList(): ManifestComponentDeletion[] {
|
|
236
|
+
return this._componentsToDelete.map((component) => ({ ...component }));
|
|
237
|
+
}
|
|
238
|
+
|
|
129
239
|
/**
|
|
130
240
|
* Returns the full manifest as a pretty-printed JSON string.
|
|
131
241
|
*
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { FunctionRuntime } from './_helpers';
|
|
2
|
-
import type
|
|
2
|
+
import { getExistingManifestContext, type ExistingManifestContextOptions } from './existing-manifest-context';
|
|
3
|
+
import type { ManifestComponentDeletion, ManifestScope } from './manifest-builder';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Initialization properties for {@link ManifestFunction}.
|
|
@@ -68,8 +69,14 @@ export interface ManifestFunctionProps {
|
|
|
68
69
|
* Defines a serverless function and registers it with the manifest.
|
|
69
70
|
*
|
|
70
71
|
* A `ManifestFunction` packages TypeScript handler code that runs on Rippling's
|
|
71
|
-
* serverless infrastructure.
|
|
72
|
-
*
|
|
72
|
+
* serverless infrastructure. The handler must export `onRipplingEvent`.
|
|
73
|
+
*
|
|
74
|
+
* Functions have two primary uses:
|
|
75
|
+
* 1. **Authoring SDUI for Custom Apps** — the function returns an SDUI spec
|
|
76
|
+
* (built with `@rippling/sdui-builder`) that renders as a page tab. Wrap the
|
|
77
|
+
* function in an {@link SduiPage} and reference it from an {@link App}.
|
|
78
|
+
* 2. **Workflow / event handlers** — functions invoked from rules, automations,
|
|
79
|
+
* or callbacks that do not render UI.
|
|
73
80
|
*
|
|
74
81
|
* This class is named `ManifestFunction` to avoid collision with the JavaScript
|
|
75
82
|
* built-in `Function`. It is also re-exported as `Function` from the barrel for
|
|
@@ -94,6 +101,15 @@ export interface ManifestFunctionProps {
|
|
|
94
101
|
* @see {@link SduiPage} — wraps a `ManifestFunction` as a navigable UI surface.
|
|
95
102
|
*/
|
|
96
103
|
export class ManifestFunction {
|
|
104
|
+
static readonly componentType = 'FUNCTION' as const;
|
|
105
|
+
|
|
106
|
+
static toDeletionIdentifier(apiName: string): ManifestComponentDeletion {
|
|
107
|
+
return {
|
|
108
|
+
type: ManifestFunction.componentType,
|
|
109
|
+
api_name: apiName,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
97
113
|
private readonly _apiName: string;
|
|
98
114
|
private readonly _name: string;
|
|
99
115
|
private readonly _code: string;
|
|
@@ -122,6 +138,30 @@ export class ManifestFunction {
|
|
|
122
138
|
scope._register(this);
|
|
123
139
|
}
|
|
124
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Loads this function from the active existing-manifest JSON context.
|
|
143
|
+
*/
|
|
144
|
+
static loadFromExisting(apiName: string, options: ExistingManifestContextOptions = {}): ManifestFunction {
|
|
145
|
+
return getExistingManifestContext(options).loadFunction(apiName);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** @internal Hydrates a function from existing manifest wire JSON. */
|
|
149
|
+
static _fromExistingComponent(scope: ManifestScope, component: Record<string, any>): ManifestFunction {
|
|
150
|
+
const props: ManifestFunctionProps = {
|
|
151
|
+
apiName: component['api_name'],
|
|
152
|
+
name: component['name'] ?? component['api_name'],
|
|
153
|
+
};
|
|
154
|
+
if (component['code_draft'] !== undefined) props.code = component['code_draft'];
|
|
155
|
+
if (component['description'] !== undefined) props.description = component['description'];
|
|
156
|
+
if (component['dependencies'] !== undefined) props.dependencies = component['dependencies'];
|
|
157
|
+
if (component['deployment_options'] !== undefined) {
|
|
158
|
+
props.deploymentOptions = component['deployment_options'];
|
|
159
|
+
}
|
|
160
|
+
if (component['allowed_domains'] !== undefined) props.allowedDomains = component['allowed_domains'];
|
|
161
|
+
if (component['is_async'] !== undefined) props.isAsync = component['is_async'];
|
|
162
|
+
return new ManifestFunction(scope, props);
|
|
163
|
+
}
|
|
164
|
+
|
|
125
165
|
/**
|
|
126
166
|
* Returns the api_name of this function (e.g. `'gym_today_schedule_fn'`).
|
|
127
167
|
*/
|
|
@@ -136,7 +176,7 @@ export class ManifestFunction {
|
|
|
136
176
|
*/
|
|
137
177
|
toDict(): Record<string, any> {
|
|
138
178
|
const component: Record<string, any> = {
|
|
139
|
-
type:
|
|
179
|
+
type: ManifestFunction.componentType,
|
|
140
180
|
name: this._name,
|
|
141
181
|
api_name: this._apiName,
|
|
142
182
|
};
|