Skip to content
Merged
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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.25.0] - 2026-03-25

### Added

- Define and "publish" new model `GetItemRequest`
- Enhance schema `getItemRequest_v2_schema` to support multiple keys
- Improve schemas `getFeatureFlagRequest_v1_schema` and `getSettingsRequest_v1_schema` by replacing anyOf with oneOf
- Improve documentation for the events `GET_STORAGE_ITEM` and `SET_STORAGE_ITEM`
- Fix model `RequireContextRequest` and the respected schema as the optional property cloudStorageKeys should conatin an array of objects and not an array of strings

## [1.24.0] - 2026-03-23

### Added
Expand Down
74 changes: 62 additions & 12 deletions docs/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,17 @@ Must be sent on application startup to get initial application context from the
}
```

The property `targetOutletName` is added automatically by the FSM-Shell in case the request is sent by an extension inside an outlet. It should not be added by the extension itself.
The property `targetOutletName` is automatically added by the FSM Shell when the request originates from an extension within an outlet. It should not be set manually by the extension. The property `cloudStorageKeys` allows you to register user setting keys that would otherwise not be accessible (see `GET_STORAGE_ITEM` and `SET_STORAGE_ITEM` for more information).

A `CloudStorageKey` is defined as follows:

```typescript
{
name: string;
dataVersion: number;
companyDependent: boolean;
}
```

* Response payload

Expand Down Expand Up @@ -305,7 +315,7 @@ Request permissions for specified object from the Shell

- ### GET_STORAGE_ITEM

With this event you can get user specific settings. You can find the available settings in the FSM admin page in "Users -> select a user -> User Settings". [Here](https://help.sap.com/viewer/fsm_admin/Cloud/en-US/users.html) you can find more information about users.
Retrieve user-specific settings from cloud storage. Available settings can be found in the FSM Admin page under "Users -> select a user -> User Settings". More details: [User Documentation](https://help.sap.com/viewer/fsm_admin/Cloud/en-US/users.html)

<!-- tabs:start -->

Expand All @@ -315,17 +325,21 @@ With this event you can get user specific settings. You can find the available s
SHELL_EVENTS.Version2.GET_STORAGE_ITEM
```

Request value stored under specified key in cloud storage
Requests values stored under one or more keys in cloud storage.

- Request payload

type: string
Key to read value from
type: GetItemRequest
Key(s) to read value from:

```typescript
string | string[]
```

- Response payload

type: GetItemResponse\<T\>
object containing key name and value which was read from requested key
Returns key-value pairs for each requested key:

```typescript
{
Expand All @@ -348,7 +362,7 @@ Request value stored under specified key in cloud storage
SHELL_EVENTS.Version1.GET_STORAGE_ITEM
```

Request value stored under specified key in cloud storage
Requests a value stored under a single key in cloud storage.

- Request payload

Expand All @@ -364,12 +378,36 @@ Request value stored under specified key in cloud storage

<!-- tabs:end -->

> Note: Below in the table you can see some common keys.
Currently, the following keys are supported out of the box:

| Key | value type | Description |
| --------------------------- | ---------- | ------------------------------------ |
| Cockpit_SelectedCompanyName | string | Name of the current selected company |
| Cockpit_SelectedLocale | string | Current selected locale |
| Key | value type | company-dependent | Description |
| ------------------------------- | ---------- | ----------------- | ------------------------------------ |
| Cockpit_SelectedCompanyName | string | no | Name of the current selected company |
| Cockpit_SelectedLanguage | string | no | Current selected language code |
| Cockpit_SelectedLocale | string | no | Current selected locale |
| Shell_IsSideNavigationCollapsed | boolean | no | Side navigation state |
| Shell_SelectedThemeId | string | no | Current selected appearance |

The keys listed above are preloaded by the Shell, as they are also used internally. Therefore, they are immediately available.

Keys can be either **company-dependent** or **company-independent**:
- **Company-dependent keys** store a separate value for each company. The value returned depends on the currently selected company.
- **Company-independent keys** share the same value across all companies.

It is also possible to fetch values for additional keys defined for a user in the Admin app. To do so, the keys must first be **registered** via the `REQUIRE_CONTEXT` event:
- The request payload of `REQUIRE_CONTEXT` includes the optional property `cloudStorageKeys`, which allows you to register non-preloaded keys.
- Once a key has been registered, its value can be retrieved using `Version2.GET_STORAGE_ITEM`.

The event `REQUIRE_CONTEXT` also allows you to register non-existing keys, which is useful for key-value pairs created at runtime:
- After registering a non-existing key, it can be accessed via `Version2.GET_STORAGE_ITEM`.
- As long as the key-value pair has not been created, the returned value will be `null`.
- Once the key-value pair is created and becomes visible in the Admin app, the actual value will be returned.

**Upcoming Change**

> **Note:** This change is currently only active when Preview Mode is enabled.

Registering keys via the `REQUIRE_CONTEXT` event will only be required for non-existing keys. All existing keys — including those not preloaded by the Shell — can be accessed directly using `Version2.GET_STORAGE_ITEM`.

- ### SET_STORAGE_ITEM

Expand All @@ -396,6 +434,18 @@ Request value stored under specified key in cloud storage
type: boolean
flag indicating if value was saved successfully

Only key-value pairs that are **preloaded by the Shell** can be updated directly. Other user settings must first be registered via the `REQUIRE_CONTEXT` event before they can be updated using `SET_STORAGE_ITEM` (see `GET_STORAGE_ITEM` for more details).

It is also possible to create new user settings:
- Like non-preloaded settings, new keys must first be registered via `REQUIRE_CONTEXT`.
- Once registered, they can be created and assigned a value using `SET_STORAGE_ITEM`.

**Upcoming Change**

> **Note:** This change is currently only active when Preview Mode is enabled.

Registering via the `REQUIRE_CONTEXT` event will only be required for new keys. All existing keys — including those not preloaded by the Shell — can be updated directly using the `SET_STORAGE_ITEM` event.

- ### GET_FEATURE_FLAG

Feature flags are internally used flags in FSM to control some new features when the preview mode is off.
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fsm-shell",
"version": "1.24.0",
"version": "1.25.0",
"description": "client library for FSM shell",
"main": "release/fsm-shell-client.js",
"module": "release/fsm-shell-client.es.js",
Expand Down
4 changes: 4 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ import {
AuthRequest,
AuthResponse,
AuthResponseType,
CloudStorageKey,
DialogSettings,
GetFeatureFlagRequest,
GetFeatureFlagsRequest,
GetFeatureFlagResponse,
GetItemRequest,
GetItemResponse,
ModalCloseRequest,
ModalOpenRequest,
Expand Down Expand Up @@ -58,10 +60,12 @@ export {
AuthRequest,
AuthResponse,
AuthResponseType,
CloudStorageKey,
DialogSettings,
GetFeatureFlagRequest,
GetFeatureFlagsRequest,
GetFeatureFlagResponse,
GetItemRequest,
GetItemResponse,
ModalCloseRequest,
ModalOpenRequest,
Expand Down
5 changes: 5 additions & 0 deletions src/models/cloud-storage/cloud-storage-key.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface CloudStorageKey {
name: string;
dataVersion: number;
companyDependent: boolean;
}
2 changes: 2 additions & 0 deletions src/models/cloud-storage/get-item-request.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

export type GetItemRequest = string | string[];
3 changes: 3 additions & 0 deletions src/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export { PermissionResponseV3 } from './permissions/permission-response.v3.model
export { Permission } from './permissions/permission.model';
export { UiPermissions } from './permissions/ui-permissions.model';

export { GetItemRequest } from './cloud-storage/get-item-request.model';
export { GetItemResponse } from './cloud-storage/get-item-response.model';
export { SetItemRequest } from './cloud-storage/set-item-request.model';

Expand Down Expand Up @@ -50,3 +51,5 @@ export { RequireContextRequest } from './require-context/require-context-request
export { Outlet } from './outlets/outlet.model';

export { TraceEntry } from './trace/trace-entry.model';

export { CloudStorageKey } from './cloud-storage/cloud-storage-key.model';
3 changes: 2 additions & 1 deletion src/models/require-context/require-context-request.model.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { AuthRequest } from '../authentication/auth-request.model';
import { CloudStorageKey } from '../cloud-storage/cloud-storage-key.model';

export interface RequireContextRequest {
clientIdentifier: string;
clientSecret: string;
cloudStorageKeys?: string[];
cloudStorageKeys?: CloudStorageKey[];
auth?: AuthRequest;
targetOutletName?: string;
targetExtensionAssignmentId?: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
export const getItemRequest_v2_schema = {
type: 'string',
oneOf: [
{
type: 'string',
},
{
type: 'array',
items: {
type: 'string',
},
},
],
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const getFeatureFlagRequest_v1_schema = {
required: ['key', 'defaultValue']
}
},
anyOf: [
oneOf: [
{
$ref: '#/$defs/payload'
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,19 @@ export const requireContextRequest_v1_schema = {
cloudStorageKeys: {
type: 'array',
items: {
type: 'string',
type: 'object',
properties: {
name: {
type: 'string'
},
dataVersion: {
type: 'number'
},
companyDependent: {
type: 'boolean'
},
},
required: ['name', 'dataVersion', 'companyDependent'],
},
},
auth: authRequest_v1_schema,
Expand Down
8 changes: 5 additions & 3 deletions src/validation/schemas/schemas.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ import { outletsRequestDynamicContextResponse_v1_schema } from './outlets/outlet
export const validAuthRequest_v1 = { response_type: 'token' };
export const validAuthResponse_v1 = { access_token: 'string', expires_in: 123, token_type: 'string' };
export const validGetItemRequest_v1 = 'string';
export const validGetItemRequest_v2 = 'string';
export const validGetItemRequest_v2_subschema_1 = 'string';
export const validGetItemRequest_v2_subschema_2 = ['string', 'string'];
export const validGetItemResponse_v2 = { key: 'string', value: {} };
export const validSetItemRequest_v1 = { key: 'string', value: {} };
export const validGetFeatureFlagRequest_v1_subschema_1 = { key: 'string', defaultValue: true };
Expand Down Expand Up @@ -89,7 +90,7 @@ export const validGetPermissionsResponse_v3 = { objectName: 'string', permission
export const validRequireContextRequest_v1 = {
clientIdentifier: 'string',
clientSecret: 'string',
cloudStorageKeys: ['string'],
cloudStorageKeys: [{ name: 'string', dataVersion: 1, companyDependent: true }],
auth: validAuthRequest_v1,
targetOutletName: 'string',
targetExtensionAssignmentId: 'string'
Expand Down Expand Up @@ -312,7 +313,8 @@ describe('Schemas', () => {
validateValidDataAgainstSchemaHelper(ajv, 'authRequest_v1_schema', authRequest_v1_schema, validAuthRequest_v1);
validateValidDataAgainstSchemaHelper(ajv, 'authResponse_v1_schema', authResponse_v1_schema, validAuthResponse_v1);
validateValidDataAgainstSchemaHelper(ajv, 'getItemRequest_v1_schema', getItemRequest_v1_schema, validGetItemRequest_v1);
validateValidDataAgainstSchemaHelper(ajv, 'getItemRequest_v2_schema', getItemRequest_v2_schema, validGetItemRequest_v2);
validateValidDataAgainstSchemaHelper(ajv, 'getItemRequest_v2_schema', getItemRequest_v2_schema, validGetItemRequest_v2_subschema_1);
validateValidDataAgainstSchemaHelper(ajv, 'getItemRequest_v2_schema', getItemRequest_v2_schema, validGetItemRequest_v2_subschema_2);
validateValidDataAgainstSchemaHelper(ajv, 'getItemResponse_v2_schema', getItemResponse_v2_schema, validGetItemResponse_v2);
validateValidDataAgainstSchemaHelper(ajv, 'setItemRequest_v1_schema', setItemRequest_v1_schema, validSetItemRequest_v1);
validateValidDataAgainstSchemaHelper(ajv, 'getFeatureFlagRequest_v1_schema', getFeatureFlagRequest_v1_schema, validGetFeatureFlagRequest_v1_subschema_1);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
export const getSettingsRequest_v1_schema = {
anyOf: [
oneOf: [
{
type: 'string'
},
{
type: 'array',
items: {
type: ['string', 'array'],
anyOf: [
oneOf: [
{
type: 'string'
},
Expand Down
Loading