Now you can assign an expiration date to each permission set or permission set group.
· To activate this feature, enable Permission Set & Permission Set Group Assignments with Expiration Dates in User Management Settings.
· If a permission set or permission set group contains any of the following permissions, it can’t have an expiration date associated with it. Assign Permission Set, Manage Profiles, Manage Users Permission Sets
· Example
o Suppose you need consultants in the San Francisco office to evaluate language used in sales contracts. Assign the consultants to a permission set group that contains the permissions that they need. When you assign the consultants to the group, specify that the assignment expires in 30 days (GMT-07:00) Pacific Daylight Time (America/Los Angeles). If you assign the permissions on June 1, the assignments expire on June 30 at 11:59 PM Pacific Time.

To obtain information about domains that Salesforce hosts for your org, use the methods in the new System.Domain class.
For example, for a sandbox domain, the getSandboxName() method returns the name of the sandbox. And the getDomainType() method returns the associated System.DomainType enum value, which represents the type of domain, such as CONTENT_DOMAIN, EXPERIENCE_CLOUD_SITES_DOMAIN, or LIGHTNING_DOMAIN.
Use the new modules LightningAlert, LightningConfirm, and LightningPrompt instead of native APIs to create notifications from your Lightning web components. Chrome and Safari plan to end support for cross-origin use of the window.alert(), window.confirm(), and window.prompt() native APIs. Each new module creates a modal that functions like its API counterpart and works in cross-origin iframes.
How: Unlike the window.*() APIs, these modules' .open() functions don’t halt execution on the page, and they each return a promise. Use async/await or .then() for any code that you want to execute after the modal closes.
These examples show how to use LightningAlert, LightningConfirm, and LightningPrompt in Lightning web components. See New and Changed Aura Components for examples using Aura syntax with the lightning:alert, lightning:confirm, and lightning:prompt components.
LightningAlert Example
This example creates an alert modal with an error message and OK button. The .open() function returns a promise that resolves when the user clicks OK.
<!-- c/myApp.html -->
<template>
<lightning-button onclick={handleAlertClick} label="Open Alert Modal">
</lightning-button>
</template>
Copy
// c/myApp.js
import { LightningElement } from 'lwc';
import LightningAlert from 'lightning/alert';
export default class MyApp extends LightningElement {
async handleAlertClick() {
await LightningAlert.open({
message: 'this is the alert message',
theme: 'error', // a red theme intended for error states
label: 'Error!', // this is the header text
});
//Alert has been closed
} }
LightningConfirm Example
This example creates a headerless confirm modal with two buttons, OK and Cancel. The .open() function returns a promise that resolves to true when the user clicks OK and false when they click Cancel.
<!-- c/myApp.html -->
<template>
<lightning-button onclick={handleConfirmClick} label="Open Confirm Modal">
</lightning-button>
</template>
Copy
// c/myApp.js
import { LightningElement } from 'lwc';
import LightningConfirm from 'lightning/confirm';
export default class MyApp extends LightningElement {
async handleConfirmClick() {
const result = await LightningConfirm.open({
message: 'this is the prompt message',
variant: 'headerless',
label: 'this is the aria-label value',
// setting theme would have no effect
});
//Confirm has been closed
//result is true if OK was clicked
//and false if cancel was clicked
}
}
LightningPrompt Example
This example creates a prompt modal with a header, message, and two buttons. If the user inputs text and clicks OK in the prompt, the .open() function returns a promise that resolves to the input value, but if the user clicks Cancel it resolves to null.
<!-- c/myApp.html -->
<template>
<lightning-button onclick={handlePromptClick} label="Open Prompt Modal">
</lightning-button>
</template>
Copy
// c/myApp.js
import { LightningElement } from 'lwc';
import LightningPrompt from 'lightning/prompt';
export default class MyApp extends LightningElement {
handlePromptClick() {
LightningPrompt.open({
message: 'this is the prompt message',
//theme defaults to "default"
label: 'Please Respond', // this is the header text
defaultValue: 'initial input value', //this is optional
}).then((result) => {
//Prompt has been closed
//result is input text if OK clicked
//and null if cancel was clicked
});
}
}
Winter 23 Reference Links
Query runs in user mode, use the WITH USER_MODE keyword in your SOQL statement.
Example: List acc = [SELECT Id FROM Account WITH USER_MODE];
DML operations, you now specify user mode as shown below.
Example
Account acc = new Account(Name='test');
insert as user acc;
Specify a delay in scheduling queueable jobs, enabling you to not consume async limits rapidly
Example
Integer delayInMinutes = 5;
ID jobID = System.enqueueJob(new MyQueueableClass(), delayInMinutes);
DynamicBinding Variables
Database.queryWithBinds, Database.getQueryLocatorWithBinds, and Database. countQueryWithBinds
Example: The SOQL query uses a bind variable for an Account name. Its value (Acme Inc.) is passed into the method using the nameBind Map. The accountName variable isn't (and doesn’t have to be) in scope when the query is executed within the method.
public static List<Account> simpleBindingSoqlQuery(Map<String, Object> bindParams) {
String queryString =
'SELECT Id, Name ' +
'FROM Account ' +
'WHERE name = :name';
return Database.queryWithBinds(
queryString,
bindParams,
AccessLevel.USER_MODE
);
}
String accountName = 'Acme Inc.';
Map<String, Object> nameBind = new Map<String, Object>{'name' => accountName};
List<Account> accounts = simpleBindingSoqlQuery(nameBind);
System.debug(accounts);
ApexTypeImplementor is now generally available and is updated
since the beta release. Use the object to find Apex classes that directly or
indirectly implement an interface. Using a SOQL query, you can get information
about public or global Apex implementors.
// Common interface that all rounding strategies will implement
public interface RoundingStratergy {
Decimal round(Decimal toRound);
}
public abstract class RoundingStrategies {
public class Ceiling implements RoundingStratergy {
public Decimal round(Decimal toRound) {
return toRound.round(System.RoundingMode.CEILING);
}
}
public class HalfDown implements RoundingStratergy {
public Decimal round(Decimal toRound) {
return toRound.round(System.RoundingMode.HALF_DOWN);
}
}
public class TwoDecimalPlaces implements RoundingStratergy {
public Decimal round(Decimal toRound) {
return toRound.setScale(2, System.RoundingMode.HALF_UP);
}
}
}
List<ApexTypeImplementor> interfaceImpls = [
SELECT ClassName, ClassNamespacePrefix
FROM ApexTypeImplementor
WHERE InterfaceName = 'RoundingStratergy' and IsConcrete=true];
// For example, an Admin could be presented with a list of Apex classes
// that could be applied. Simulated selection of 2 decimal places
ApexTypeImplementor selectedRoundingStratergy = interfaceImpls[2];
System.assertEquals('RoundingStrategies.TwoDecimalPlaces',
selectedRoundingStratergy.ClassName);
// Create an instance of the class that implements the interface
RoundingStratergy rs = (RoundingStratergy) Type.forName(selectedRoundingStratergy.ClassNamespacePrefix,
selectedRoundingStratergy.ClassName).newInstance();
Decimal rounded = rs.round(7.1459);
System.assertEquals(7.15, rounded);
getSObjectType()
Use the new getSObjectType() method to get the SObjectType of a Schema.DescribeFieldResult object. The returned type is that of the
source sObject describe object that was originally retrieved, eliminating the
need for additional mechanisms to determine parent relationships.
This
example uses the getSObjectType() method
to create a Salesforce object of the same type as the passed in field’s
originating object and then dynamically populates the field’s value.
public class ObjectCreator { public static sObject createAndSet(Schema.sObjectField field, object fieldValue) { Schema.DescribeFieldResult fieldDescribe = field.getDescribe(); Schema.sObjectType sourceType = fieldDescribe.getSObjectType(); sObject newObj = sourceType.newSObject(null, true); newObj.put(field, fieldValue); return newObj; }}
Here’s
how to call the sample createAndSet() method.
sObject o = ObjectCreator.createAndSet(Account.Industry, 'Development');Assert.isInstanceOfType(o, Account.class);Assert.areEqual('Development', ((Account)o).Industry);
The lwc:if, lwc:elseif, and lwc:else conditional directives supersede the
legacy if:true and if:else directives.
Previously, chaining if:true and if:false blocks introduced performance cost and resulted in the
property getters getting called multiple times.
<!-- legacyConditional.html --><template> <!---Replace if:true with lwc:if--> <template if:true={isTemplateOne}> This is template one. </template> <!-- Replace if:false with lwc:else --> <template if:false={isTemplateOne}> This is template two. </template></template>
Update
With
the lwc:if, lwc:elseif,
and lwc:else conditional
directives, the property getters are accessed only one time per instance of the
directive.
<!-- conditionalExample.html --><template> <template lwc:if={isTemplateOne}> This is template one. </template> <template lwc:else> This is template two.</template>
Both lwc:elseif and lwc:else must
be immediately preceded by a sibling lwc:if or lwc:elseif.
Pass
in an expression to lwc:if and lwc:elseif,
but not to lwc:else.
If expression1 returns
a truthy, none of the other property getters are accessed.
<!-- example.html --><template> <template lwc:if={expression1}> Statement 1 </template> <template lwc:elseif={expression2}> Statement 2 </template> <template lwc:else> Statement 3 </template></template>