Skip to content

Commit

Permalink
Add messages to handle MODAL open and close event
Browse files Browse the repository at this point in the history
  • Loading branch information
Sébastien Barbier committed Mar 31, 2021
1 parent 110c757 commit 4f6172a
Show file tree
Hide file tree
Showing 12 changed files with 131 additions and 7 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ 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.10.0] - 2021-04-01

### Added

- Messages to handle MODAL open and close event

## [1.9.2] - 2021-02-25

### Fixed
Expand Down
39 changes: 38 additions & 1 deletion docs/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Must be sent on application startup to get initial application context from the
}
```

The property `authToken` can only be accessed by applications and will not be exposed to extensions. Extensions should require an access_token using the auth value. _Also see [REQUIRE_AUTHENTICATION](#REQUIRE_AUTHENTICATION) event_
The property `authToken` can only be accessed by applications and will not be exposed to extensions. Extensions should require an access*token using the auth value. \_Also see [REQUIRE_AUTHENTICATION](#REQUIRE_AUTHENTICATION) event*

REQUIRE_CONTEXT will first return the response payload, then trigger individual ViewState object as describe in the ViewState section.

Expand Down Expand Up @@ -320,6 +320,43 @@ Request value stored under specified key in cloud storage
});
```

## Modal specific events

Applciations can request do display a modal with a specified URL. Events include opening, closing, and confirmation a modal has been closed.

- ### MODAL.OPEN

Open a modal using `SHELL_EVENTS.Version1.MODAL.OPEN` event from your application. You can specify `modalSettings` like at title or size.

```
this.sdk.emit(SHELL_EVENTS.Version1.MODAL.OPEN, {
url: 'https://example.com'
modalSettings: {
title: 'My title',
size: 'l'| 'm'|'s',
}
});
```

- ### MODAL.CLOSE

Request closing of the open modal using `SHELL_EVENTS.Version1.MODAL.CLOSE` from your application or the opened modal. An object can be passed as parameter to be send back to the application which opened the modal.

```
this.sdk.emit(SHELL_EVENTS.Version1.MODAL.CLOSE, {
[key: string]: any
});
```

An application can listen to the same event to trigger code on closing. This event is only received if the application emited the OPEN event.

```typescript
this.sdk.on(SHELL_EVENTS.Version1.MODAL.CLOSED, (content) => {
// React to the he closing of the app
// If MODAL.CLOSE was passed an argument, it will be provided here.
});
```

## Extension specific events

ShellSdk provide a set of features which are specifically designed to allow communications with extensions running inside an application.
Expand Down
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.9.2",
"version": "1.10.0",
"description": "client library for FSM shell",
"main": "release/fsm-shell-client.js",
"module": "release/fsm-shell-client.es.js",
Expand Down
6 changes: 6 additions & 0 deletions src/ShellEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export type EventType =
| 'V1.OUTLET.REQUEST_CONTEXT'
| 'V1.OUTLET.LOADING_SUCCESS'
| 'V1.OUTLET.LOADING_FAIL'
| 'V1.MODAL.OPEN'
| 'V1.MODAL.CLOSE'
| string;

export const SHELL_EVENTS = {
Expand All @@ -44,6 +46,10 @@ export const SHELL_EVENTS = {
LOADING_SUCCESS: 'V1.OUTLET.LOADING_SUCCESS',
LOADING_FAIL: 'V1.OUTLET.LOADING_FAIL',
},
MODAL: {
OPEN: 'V1.MODAL.OPEN',
CLOSE: 'V1.MODAL.CLOSE',
},
},
Version2: {
GET_STORAGE_ITEM: 'V2.GET_STORAGE_ITEM',
Expand Down
12 changes: 11 additions & 1 deletion src/ShellSdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,14 +306,24 @@ export class ShellSdk {
return;
}

let from = payload.from || [];

// If it come from an outlet
if (payload.type === SHELL_EVENTS.Version1.SET_VIEW_STATE) {
console.warn(
'[ShellSDk] A plugin tried to update viewState using SetViewState which is not allowed for security reason.'
);
return;
} else if (
payload.type === SHELL_EVENTS.Version1.MODAL.OPEN &&
from.length === 0 &&
!this.allowedOrigins.some((o) => payload.value.url.startsWith(o))
) {
// If we are not root and first to receive OPEN, we block request opening a modal which has a different
// origin than the one allowed by the outlet
console.warn('[ShellSDk] MODAL OPEN url is not in allowedList.');
return;
}
let from = payload.from || [];
// If we receive from outlet request_context to fetch plugin from target, we return LOADING_FAIL
// if too many depth exchanges
if (
Expand Down
4 changes: 2 additions & 2 deletions src/ShellVersionInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
// MANUAL CHANGES TO THIS FILE WILL BE OVERWRITTEN !!!

export const SHELL_VERSION_INFO = {
VERSION: 'Will-Be-Replaced-During-Build',
BUILD_TS: 'Will-Be-Replaced-During-Build',
VERSION: '1.10.0',
BUILD_TS: '2021-03-31T16:14:15.987Z',
};
4 changes: 4 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {
AuthResponseType,
AuthRequest,
AuthResponse,
ModalOpenRequest,
ModalSize,
} from './models/index';

export {
Expand All @@ -42,4 +44,6 @@ export {
AuthResponseType,
AuthRequest,
AuthResponse,
ModalOpenRequest,
ModalSize,
};
2 changes: 2 additions & 0 deletions src/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export { UiPermissions } from './permissions/ui-permissions.model';
export { GetItemResponse } from './cloud-storage/get-item-response.model';
export { SetItemRequest } from './cloud-storage/set-item-request.model';

export { ModalSize, ModalOpenRequest } from './modal/modal-open-request.model';

export { SettingsResponse } from './settings/settings-response.model';

export { GetFeatureFlagRequest } from './feature-flag/get-feature-flag-request.model';
Expand Down
3 changes: 3 additions & 0 deletions src/models/modal/modal-close-request.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface ModalCloseRequest<T> {
[key: string]: any;
}
8 changes: 8 additions & 0 deletions src/models/modal/modal-open-request.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export type ModalSize = 'l' | 'm' | 's';
export interface ModalOpenRequest<T> {
url: string;
modalSettings?: {
title?: string;
size?: ModalSize;
};
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

export interface OutletsDeleteAssignmentResponse<T> {
target: string,
target: string;
error?: string;
}
49 changes: 49 additions & 0 deletions src/tests/Outlets.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -397,4 +397,53 @@ describe('Outlets', () => {
expect(postMessageParent.called).toBe(false);
expect(postMessageOutlet.called).toBe(true);
});

it('should only open modals with url from allowedOrigins', () => {
const postMessageParent = sinon.spy();
sdk = ShellSdk.init(
({
postMessage: postMessageParent,
} as any) as Window,
sdkOrigin,
windowMock
);
sdk.setAllowedOrigins([EXTENSION_ORIGIN]);

const postMessageOutlet = sinon.spy();
const iframe = ({
src: EXTENSION_SRC,
contentWindow: ({
postMessage: postMessageOutlet,
} as any) as Window,
} as any) as HTMLIFrameElement;
sdk.registerOutlet(iframe);

const requestContext = sinon.spy();

windowMockCallback({
source: iframe.contentWindow,
origin: EXTENSION_ORIGIN,
data: {
type: SHELL_EVENTS.Version1.MODAL.OPEN,
value: {
url: EXTENSION_ORIGIN + '/my-modal-url/',
},
},
});
expect(postMessageParent.called).toBe(true);
postMessageParent.resetHistory();

windowMockCallback({
source: iframe.contentWindow,
origin: EXTENSION_ORIGIN,
data: {
type: SHELL_EVENTS.Version1.MODAL.OPEN,
value: {
url: 'https://example.com/my-modal-url/',
},
},
});
expect(postMessageParent.called).toBe(false);
postMessageParent.resetHistory();
});
});

0 comments on commit 4f6172a

Please sign in to comment.