Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
"tsdown": "0.16.4",
"typedoc": "^0.28.12",
"typedoc-plugin-rename-defaults": "^0.7.0",
"typescript": "`^5.9",
"typescript": "^5.9",
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't noticed when this typo creaped in, thanks for addressing it.

"typescript-eslint": "^8.1.0"
},
"pnpm": {
Expand Down
33 changes: 27 additions & 6 deletions packages/omniscript/src/omniScriptAccess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,30 @@ interface OmniScriptFindOptions {
*/
export class OmniScriptAccess {

private isOmniProcessSObjectExists?: boolean = undefined;
private isOmniScriptSObjectExists?: boolean = undefined;

constructor(
private readonly salesforceService: SalesforceService,
private readonly lookupService: SalesforceLookupService,
private readonly schema: SalesforceSchemaService
) {
}

private async hasOmniProcessSObject() {
if (this.isOmniProcessSObjectExists === undefined) {
this.isOmniProcessSObjectExists = await this.schema.isSObjectDefined(OmniProcessRecord.SObjectType);
}
return this.isOmniProcessSObjectExists;
}

private async hasOmniScriptSObject() {
if (this.isOmniScriptSObjectExists === undefined) {
this.isOmniScriptSObjectExists = await this.schema.isSObjectDefined(OmniScriptRecord.SObjectType);
}
return this.isOmniScriptSObjectExists;
}

/**
* Filter OmniScripts based on specified criteria. This method searches across both
* OmniProcess and OmniScript SObjects and returns matching records.
Expand Down Expand Up @@ -106,11 +123,15 @@ export class OmniScriptAccess {
public async filter(filter?: OmniScriptIdentifier, options?: OmniScriptFilterOptions): Promise<OmniScriptRecord[]>;
public async filter(filter?: OmniScriptIdentifier, options?: OmniScriptFilterOptions): Promise<OmniScriptRecord[]> {
const scripts: OmniScriptRecord[] = [];
for (const record of await this.queryOmniProcessRecords(filter)) {
scripts.push(OmniScriptRecord.fromProcess(record));
if (await this.hasOmniProcessSObject()) {
for (const record of await this.queryOmniProcessRecords(filter)) {
scripts.push(OmniScriptRecord.fromProcess(record));
}
}
for (const record of await this.queryOmniScriptRecords(filter)) {
scripts.push(OmniScriptRecord.fromScript(record));
if (await this.hasOmniScriptSObject()) {
for (const record of await this.queryOmniScriptRecords(filter)) {
scripts.push(OmniScriptRecord.fromScript(record));
}
}
return options?.withElements ? this.attachElements(scripts) : scripts;
}
Expand Down Expand Up @@ -158,12 +179,12 @@ export class OmniScriptAccess {
criteria.id = undefined;
}

const processRecords = await this.queryOmniProcessRecords(id, { limit: 1 });
const processRecords = await this.hasOmniProcessSObject() ? await this.queryOmniProcessRecords(id, { limit: 1 }) : [];
if (processRecords.length) {
scriptRecord = OmniScriptRecord.fromProcess(processRecords[0]);
}

const scriptRecords = await this.queryOmniScriptRecords(id, { limit: 1 });
const scriptRecords = await this.hasOmniScriptSObject() ? await this.queryOmniScriptRecords(id, { limit: 1 }) : [];
if (scriptRecords.length) {
scriptRecord = OmniScriptRecord.fromScript(scriptRecords[0]);
}
Expand Down
21 changes: 16 additions & 5 deletions packages/salesforce/src/deploy/packageBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,9 +288,14 @@ export class SalesforcePackageBuilder {
}

if (metadataType.isBundle) {
// Only Aura and LWC are bundled at this moment
// Experience Bundle, Digital Experience Bundles, Only Aura and LWC are bundled at this moment
// Classic metadata package all related files
await this.addBundledSources(path.dirname(file), metadataType);
if (metadataType.id === 'experiencebundle' && file.endsWith('-meta.xml')) {
await this.addBundledSources(file.replace(/-meta\.xml$/ig, '').split('.').shift()!, metadataType);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use this.stripFileExtension(file, 2) to drop .XX-meta.xml

}
else {
await this.addBundledSources(path.dirname(file), metadataType);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a test method for this use case? For changes to the package builder I'd like to have test cases which will also prevent the feature from breaking in the future. There is an existing test class that you can extend.

}
}

// add source
Expand Down Expand Up @@ -421,14 +426,17 @@ export class SalesforcePackageBuilder {
return false;
}

private async addBundledSources(bundleFolder: string, metadataType: MetadataType) {
private async addBundledSources(bundleFolder: string, metadataType: MetadataType, componentName?: string) {
const bundleFiles = await this.fs.readDirectory(bundleFolder);
const componentName = bundleFolder.split(/\\|\//g).pop()!;
componentName = componentName ?? bundleFolder.split(/\\|\//g).pop();
for (const file of bundleFiles) {
const fullPath = path.join(bundleFolder, file.name);
if (file.isFile() && this.addParsedFile(fullPath)) {
await this.addSingleSourceFile(fullPath, metadataType, componentName);
}
if (file.isDirectory()) {
await this.addBundledSources(fullPath, metadataType, componentName);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doens't this also flatten nested structures in for example LWC bundles? And is that wanted, how would it affect __test__ folders in LWC bundles?

}
}
}

Expand Down Expand Up @@ -821,6 +829,9 @@ export class SalesforcePackageBuilder {
const componentName = sourceFileName.replace(/\.[^.]+$/ig, '');

if (metadataType.isBundle) {
if (metadataType.id == 'experiencebundle' || metadataType.id == 'digitalexperiencebundle') {
return sourceFileName.split('.').shift()!;
}
return metaFile.split(/\\|\//g).slice(-2).shift()!;
}

Expand Down Expand Up @@ -848,7 +859,7 @@ export class SalesforcePackageBuilder {
}

if (metadataType.isBundle && componentPackageFolder) {
const componentName = fullSourcePath.split(/\\|\//g).slice(-2).shift()!;
const componentName = this.getPackageComponentName(fullSourcePath, metadataType);
return path.posix.join(componentPackageFolder, componentName);
}

Expand Down
10 changes: 9 additions & 1 deletion packages/vlocity-deploy/src/deploymentSpecs/vlocityCard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import { DatapackDeploymentRecord, DeploymentStatus } from '../datapackDeploymen
import { forEachAsyncParallel, getErrorMessage, Iterable, Timer } from '@vlocode/util';
import { SalesforceDeployService, SalesforcePackage } from '@vlocode/salesforce';
import { FlexCardActivator } from '../flexCard/flexCardActivator';
import { RecordActivator } from './recordActivator';
import { Container, Logger } from '@vlocode/core';

@deploymentSpec({ recordFilter: /^VlocityCard__c$/i })
export class VlocityUILayoutAndCards implements DatapackDeploymentSpec {

public constructor(
private readonly activator: FlexCardActivator,
private readonly recordActivator: RecordActivator,
private readonly logger: Logger,
private readonly container: Container,
) { }
Expand Down Expand Up @@ -71,7 +73,13 @@ export class VlocityUILayoutAndCards implements DatapackDeploymentSpec {

public async afterDeploy(event: DatapackDeploymentEvent) {
const packages = new Array<SalesforcePackage>();

await this.recordActivator.activateRecords(
Iterable.filter(
event.getDeployedRecords('VlocityCard__c'),
record => record.value('CardType__c') !== 'flex'
),
() => ({ Active__c: true })
);
await forEachAsyncParallel(
Iterable.filter(
event.getDeployedRecords('VlocityCard__c'),
Expand Down
98 changes: 63 additions & 35 deletions packages/vlocity-deploy/src/flexCard/flexCardDefinition.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { injectable } from "@vlocode/core";
import { QueryBuilder, RecordFactory, SalesforceService } from "@vlocode/salesforce";
import { QueryBuilder, RecordFactory, SalesforceSchemaService, SalesforceService } from "@vlocode/salesforce";
import { asString } from "@vlocode/util";
import { VlocityDatapack } from "@vlocode/vlocity";

Expand Down Expand Up @@ -33,15 +33,15 @@ interface OmniUiCardRecord {
}

interface VlocityCardRecord {
Name: string;
Id: string;
Author: string;
Active: boolean;
Version: number;
IsChildCard: boolean;
CardType: 'flex' | 'classic';
Definition: string | object;
Styles?: string;
name: string;
id: string;
author: string;
active: boolean;
version: number;
isChildCard: boolean;
cardType: 'flex' | 'classic';
definition: string | object;
styles?: string;
}

export namespace FlexCardDefinition {
Expand Down Expand Up @@ -119,15 +119,15 @@ export namespace FlexCardDefinition {
return {
SObjectType: '%vlocity_namespace%__VlocityCard__c',
ActivationField: '%vlocity_namespace%__Active__c',
Name: record.Name,
Id: record.Id,
VersionNumber: record.Version,
AuthorName: record.Author,
IsActive: record.Active === undefined ? true : record.Active,
IsChildCard: record.IsChildCard,
Type: record.CardType,
PropertySetConfig: asString(record.Definition),
StylingConfiguration: parseAsJsonString(record.Styles)
Name: record.name,
Id: record.id,
VersionNumber: record.version,
AuthorName: record.author,
IsActive: record.active === undefined ? true : record.active,
IsChildCard: record.isChildCard,
Type: record.cardType,
PropertySetConfig: asString(record.definition),
StylingConfiguration: parseAsJsonString(record.styles)
};
}

Expand Down Expand Up @@ -156,7 +156,24 @@ export type FlexCardIdentifier = string | { name: string, isChildCard?: boolean,
@injectable.singleton()
export class FlexCardDefinitionAccess {

constructor(private readonly salesforceService: SalesforceService) {
private isOmniUiCardSObjectExists?: boolean = undefined;
private isVlocityCardSObjectExists?: boolean = undefined;

constructor(private readonly salesforceService: SalesforceService, private readonly salesforceSchemaService: SalesforceSchemaService) {
}

private async hasOmniUiCardSObject() {
if (this.isOmniUiCardSObjectExists === undefined) {
this.isOmniUiCardSObjectExists = await this.salesforceSchemaService.isSObjectDefined('OmniUiCard');
}
return this.isOmniUiCardSObjectExists;
}

private async hasVlocityCardSObject() {
if (this.isVlocityCardSObjectExists === undefined) {
this.isVlocityCardSObjectExists = await this.salesforceSchemaService.isSObjectDefined('%vlocity_namespace%__VlocityCard__c');
}
return this.isVlocityCardSObjectExists;
}

/**
Expand All @@ -174,11 +191,15 @@ export class FlexCardDefinitionAccess {
*/
public async getFlexCardDefinitions(criteria?: FlexCardIdentifier): Promise<Map<string, FlexCardDefinition>> {
const cards: FlexCardDefinition[] = [];
for (const record of await this.queryOmniCardRecords(criteria)) {
cards.push(FlexCardDefinition.fromOmniCard(record));
if (await this.hasOmniUiCardSObject()) {
for (const record of await this.queryOmniCardRecords(criteria)) {
cards.push(FlexCardDefinition.fromOmniCard(record));
}
}
for (const record of await this.queryVlocityCardRecords(criteria)) {
cards.push(FlexCardDefinition.fromVlocityCard(record));
if (await this.hasVlocityCardSObject()) {
for (const record of await this.queryVlocityCardRecords(criteria)) {
cards.push(FlexCardDefinition.fromVlocityCard(record));
}
}
const cardsByName = new Map<string, FlexCardDefinition>();
for (const card of cards) {
Expand All @@ -200,11 +221,15 @@ export class FlexCardDefinitionAccess {
*/
public async filterCardDefinitions(filter?: FlexCardIdentifier): Promise<FlexCardDefinition[]> {
const cards: FlexCardDefinition[] = [];
for (const record of await this.queryOmniCardRecords(filter)) {
cards.push(FlexCardDefinition.fromOmniCard(record));
if (await this.hasOmniUiCardSObject()) {
for (const record of await this.queryOmniCardRecords(filter)) {
cards.push(FlexCardDefinition.fromOmniCard(record));
}
}
for (const record of await this.queryVlocityCardRecords(filter)) {
cards.push(FlexCardDefinition.fromVlocityCard(record));
if (await this.hasVlocityCardSObject()) {
for (const record of await this.queryVlocityCardRecords(filter)) {
cards.push(FlexCardDefinition.fromVlocityCard(record));
}
}
return cards;
}
Expand All @@ -218,16 +243,19 @@ export class FlexCardDefinitionAccess {
* @throws Error when no FlexCard record is found for the provided identifier
*/
public async findCardDefinition(id: FlexCardIdentifier): Promise<FlexCardDefinition> {
const omniCardRecords = await this.queryOmniCardRecords(id);
if (omniCardRecords.length) {
return FlexCardDefinition.fromOmniCard(omniCardRecords[0]);
if (await this.hasOmniUiCardSObject()) {
const omniCardRecords = await this.queryOmniCardRecords(id);
if (omniCardRecords.length) {
return FlexCardDefinition.fromOmniCard(omniCardRecords[0]);
}
}

const vlocityCardRecords = await this.queryVlocityCardRecords(id);
if (vlocityCardRecords.length) {
return FlexCardDefinition.fromVlocityCard(vlocityCardRecords[0]);
if (await this.hasVlocityCardSObject()) {
const vlocityCardRecords = await this.queryVlocityCardRecords(id);
if (vlocityCardRecords.length) {
return FlexCardDefinition.fromVlocityCard(vlocityCardRecords[0]);
}
}

throw new Error(`No FlexCard record found for ID: ${JSON.stringify(id)}`);
}

Expand Down
22 changes: 19 additions & 3 deletions packages/vlocity-deploy/src/flexCard/flexCardDesignerUtil.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable */
import { LightningComponentBundle } from "@vlocode/salesforce";
import { LightningComponentBundle, SalesforceLabels } from "@vlocode/salesforce";
import { container } from "@vlocode/core";
import { deepClone, XML } from "@vlocode/util";

namespace lodash {
Expand Down Expand Up @@ -916,6 +917,7 @@ export namespace FlexCardDesigner {
});
return sessionHandler;
}

function getCustomLabelTrackVariable(customLabels) {
if (customLabels && Object.keys(customLabels).length > 0) {
let variableString = "@track Label={";
Expand Down Expand Up @@ -1184,7 +1186,7 @@ export namespace FlexCardDesigner {
}

//get all components files
export function generateLWCFiles(lwcComponentName, item, type, mode = null, metaObject) {
export async function generateLWCFiles(lwcComponentName, item, type, mode = null, metaObject) {
let files: any[] = [];
let jsSource, defSource, htmlSource, cssSource, styleDefSource, xmlSource;
let actualNsPrefix = nsPrefix; //for restoring nsPrefix later
Expand All @@ -1204,7 +1206,7 @@ export namespace FlexCardDesigner {
let cardRecordId = item.Id;
if (type === "card" && !isStdRuntime) {
htmlSource = generateCardHtml(layoutDefinition, theme, item);
jsSource = generateCardJs(lwcComponentName, theme, item.Label, layoutDefinition, cardRecordId, customCssAttachmentId);
jsSource = generateCardJs(lwcComponentName, theme, await getCustomLabelsFromCardDefinition(item), layoutDefinition, cardRecordId, customCssAttachmentId);
cssSource = typeof item.StylingConfiguration === "string" ? JSON.parse(item.StylingConfiguration).customStyles ? JSON.parse(item.StylingConfiguration).customStyles : "/*Custom Styles*/" : item.StylingConfiguration ? item.StylingConfiguration.customStyles ? item.StylingConfiguration.customStyles : "/*Custom Styles*/" : "/*Custom Styles*/";
defSource = generateDefinition(item);
styleDefSource = generataStyleDefinition();
Expand Down Expand Up @@ -1280,6 +1282,20 @@ export namespace FlexCardDesigner {
return files;
}

async function getCustomLabelsFromCardDefinition(cardDef) {
if (cardDef.Label) {
return cardDef.Label;
}

const labelRegex = /\{(Label\.[^}]+)\}/g;
const matches = [...JSON.stringify(cardDef).matchAll(labelRegex)].map(m => m[1].substring(6)); // Extract "Label.namespace.labelName" or "Label.labelName"
const labelKeys = Array.from(new Set(matches));
const salesforceLabelsService = container.get(SalesforceLabels);
return Object.fromEntries(
Object.entries(await salesforceLabelsService.getCustomLabels(labelKeys)).map(([key, label]) =>[key, label.value]
));
}

function getDevNamefromCardname(cardName) {
const name = downloadMode === DOWNLOAD_OFF_PLATFORM_MODE ? cardName : lwcPrefix + "-" + cardName;
return convertNameToValidLWCCase(name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export class FlexCardLwcCompiler {
const files: Array<{
filepath: string,
source: string
}> = compiler.generateLWCFiles(name, card, 'card', null, metaObject);
}> = await compiler.generateLWCFiles(name, card, 'card', null, metaObject);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of calling getCustomLabelsFromCardDefinition in the flexCardDesignerUtil.ts can you move it into flexCardLwcCompiler.ts‎. The flexCardDesignerUtil is sourced from the org and will be with SF releases, for ease of updating we should avoid updating it.


return {
name: name,
Expand Down
Loading