quilt
Search…
Embed
The Quilt catalog has limited-feature S3 browser called Embed, an embeddable iframe. Embed is served off the main catalog under /__embed route.

Usage

Here's a sample code snippet in plain JavaScript + React that outlines the basic use cases:
1
import * as React from 'react'
2
3
const EMBED_ORIGIN = 'https://my-quilt-catalog'
4
const PARENT_ORIGIN = window.location.origin
5
const EVENT_SOURCE = 'quilt-embed'
6
7
const mkNonce = () => `${Math.random()}`.slice(2)
8
9
function Embed() {
10
const iframeRef = React.useRef(null)
11
12
const [nonce, setNonce] = React.useState(mkNonce)
13
14
// nonce is used to identify "our" Embed instance and make sure we're receiving messages from the same instance
15
// origin must be sent as a query parameter to enable cross-origin message passing from Embed to the parent
16
const src = `${EMBED_ORIGIN}/__embed?nonce=${nonce}&origin=${encodeURIComponent(PARENT_ORIGIN)}`
17
18
const postMessage = React.useCallback(
19
// function for sending messages to the Embed (it will only handle messages sent by the window that opened it aka parent)
20
(msg) => {
21
if (!iframeRef.current) return
22
// origin must be sent as a second parameter to enable cross-origin message passing
23
iframeRef.current.contentWindow.postMessage(msg, EMBED_ORIGIN)
24
},
25
[iframeRef],
26
)
27
28
const initialize = React.useCallback(() => {
29
// see the `init` command reference in the API section below for details
30
postMessage({
31
type: 'init',
32
bucket: 'your-bucket-here',
33
path: 'path-to-object-or-prefix',
34
// deep linking can be implemented by storing Embed's route and then initializing it with this stored route
35
route: location.search.route || undefined,
36
37
// e.g. { provider, token } for SSO or { password, username } (which doesn't seem like a right choice in most cases)
38
// getting credentials is your app's responsibility
39
credentials: { provider: 'okta', token: 'my token' },
40
41
theme: {
42
palette: {
43
primary: {
44
main: '#282b50',
45
},
46
secondary: {
47
main: '#339933',
48
},
49
},
50
typography: {
51
fontFamily: '"Comic Sans MS", "Comic Sans", cursive',
52
},
53
},
54
55
overrides: {
56
s3ObjectLink: {
57
href: 'https://my-app/s3-browser?route=<%= encodeURIComponent(url) %>',
58
// notification shown after copying href to the clipboard (if `emit` is not set to "override")
59
emit: 'override',
60
},
61
},
62
63
// arbitrary CSS files can be injected to further customize look and feel and/or layout
64
css: [
65
'https://my-cdn.com/my-custom-styles-1.css',
66
'https://my-other-host.com/my-custom-styles-2.css',
67
],
68
})
69
}, [postMessage])
70
71
const navigate = React.useCallback((route) => {
72
// command the Embed to navigate to an arbitrary route
73
postMessage({ type: 'navigate', route })
74
}, [postMessage])
75
76
const reloadIframe = React.useCallback(() => {
77
// reload the iframe by generating a new nonce (and therefore changing `src` computed value)
78
setNonce(mkNonce)
79
}, [setNonce])
80
81
const handleMessage = React.useCallback(
82
(e) => {
83
if (
84
// ignore messages from other windows
85
e.source !== iframeRef.current.contentWindow ||
86
// ensure origin is what we expect it to be (user has not navigated away)
87
e.origin !== EMBED_ORIGIN ||
88
// ensure the message has expected format (.source set to 'quilt-embed')
89
e.data.source !== EVENT_SOURCE ||
90
// ensure this is "our" instance by comparing nonce passed to the iframe
91
// via query string to the nonce passed back by the iframe
92
nonce !== e.data.nonce
93
) {
94
return
95
}
96
// handle messages from the Embed
97
switch (e.data.type) {
98
case 'error':
99
console.error(e.data.message, e.data)
100
return
101
case 'ready':
102
initialize()
103
return
104
case 'navigate':
105
// store Embed state (route), e.g. update our URL to store the embed route in a query paramter or smth
106
console.log('embed navigating to', e.data.route)
107
return
108
case 's3ObjectLink':
109
// construct a custom link using e.data and copy it to clipboard or perform any other relevant action
110
console.log('s3 object link clicked', e.data)
111
return
112
}
113
},
114
[iframeRef, nonce, initialize],
115
)
116
117
React.useEffect(() => {
118
// subscribe to messages from Embed
119
window.addEventListener('message', handleMessage)
120
return () => {
121
window.removeEventListener('message', handleMessage)
122
}
123
}, [handleMessage])
124
125
return (
126
<iframe
127
ref={iframeRef}
128
src={src}
129
width="900"
130
height="600"
131
// other things like styling and stuff
132
/>
133
)
134
}
Copied!

API reference

URL and query parameters

The Embed is served off the main catalog server under /__embed route which takes two optional query parameters:
nonce (any unique string) is used to identify "our" Embed instance and make sure we're receiving messages from that same instance.
origin must be sent to enable cross-origin message passing from Embed to the parent.

Commands to Embed

Embed accepts commands from the parent via postMessage API. Command message data format:
1
interface Command {
2
type: string
3
// ...parameters
4
}
Copied!
Available commands are listed below.
init
Initialize the Embed. This command must be sent after the Embed is ready (see ready message reference for details). Supported SSO providers are listed in the Technical Reference.
1
interface InitCommand extends Command {
2
type: 'init'
3
4
// Bucket name, e.g. 'my-bucket'
5
bucket?: string
6
// Path to object or prefix in the given bucket, e.g. 'some-prefix/some-object.csv'
7
path?: string
8
9
// Initial route Embed will navigate to, e.g. '/b/my-bucket/tree/some/path',
10
// takes precedence over bucket / path
11
route?: string
12
13
// Embed accepts any credentials supported by the Quilt authentication endpoint,
14
// e.g. { provider, token } for [SSO](../technical-reference.md#single-sign-on-sso)
15
// or { password, username } (which doesn't seem like a right choice in most cases tho).
16
// Getting credentials is your app's responsibility.
17
credentials: { provider: string; token: string } | { username: string; password: string }
18
19
// Embed can be "scoped" to a prefix, meaning that prefix will be a virtual "root" for the object browser,
20
// but only for display purposes (i.e. formatting paths / rendering breadcrumbs),
21
// it won't prevent navigating to the paths outside the scope if navigated directly
22
// via a command (navigate or init) or a link, so it's not to be considered a security measure.
23
scope?: string
24
25
// Look and feel of the Embed can be customzied by providing theme overrides,
26
// see [MUI theming reference](https://material-ui.com/customization/theming/)
27
// and [Quilt theme construction code](https://github.com/quiltdata/quilt/blob/master/catalog/app/constants/style.js#L145)
28
// for details.
29
theme?: MUI.ThemeOptions // https://github.com/mui-org/material-ui/blob/v4.12.3/packages/material-ui/src/styles/createTheme.d.ts#L15
30
31
// Some aspects of the UI can be overriden:
32
overrides?: {
33
// This prop is responsible for customizing the display and behaviour
34
// of the "link" button in the object revision list menu
35
s3ObjectLink?: {
36
// Title of the link element
37
title?: string
38
// Link [template](https://lodash.com/docs/4.17.15#template).
39
// Template context:
40
// url: string -- url / route of the object version in the context of the Embed
41
// s3HttpsUri: string -- HTTPS URI of the object version, e.g. https://my-bucket.s3.amazonaws.com/${key}?versionId=${version} (with properly encoded key)
42
// bucket: string -- current bucket
43
// key: string -- key of the browsed object
44
// version: string -- object version id
45
// Example: 'https://my-app/s3-browser?route=<%= encodeURIComponent(url) %>'
46
href?: string
47
// Notification shown after copying href to the clipboard (if `emit` is not set to "override")
48
notification?: string
49
// Set to "notify" or "override" to enable Embed sending "s3ObjectLink" messages
50
// (otherwise those messages won't be sent).
51
// Set to "override" to disable default action on click (copying href to clipboard).
52
emit?: 'notify' | 'override' | null
53
}
54
}
55
56
// List of CSS URLs to be injected (to further customize look and feel and/or layout)
57
// Example:
58
// [
59
// 'https://my-cdn.com/my-custom-styles-1.css',
60
// 'https://my-other-host.com/my-custom-styles-2.css',
61
// ],
62
css?: string[]
63
}
Copied!
navigate
Navigate to the given route.
1
interface NavigateCommand extends Command {
2
type: 'navigate'
3
// Route to navigate to, e.g. '/b/my-bucket/tree/some/path'
4
route: string
5
}
Copied!

Messages from Embed

Embed sends messages to its parent via postMessage API. Message data format:
1
interface Message {
2
source: 'quilt-embed'
3
nonce: string
4
type: string
5
// ...parameters
6
}
Copied!
Available messages are listed below.
ready
Sent when the Embed is done loading and ready to receive commands (waiting for init command).
1
interface ReadyMessage extends Message {
2
type: 'ready'
3
}
Copied!
error
Sent when an error occurs.
1
interface ErrorMessage extends Message {
2
type: 'error'
3
message: string
4
credentials?: object // for authentication error
5
init?: object // for initialization error
6
data?: object // for navigation error
7
}
Copied!
navigate
Sent when the Embed navigates to a new route. Useful for syncing Embed state with the parent app state.
1
interface NavigateMessage extends Message {
2
type: 'navigate'
3
route: string
4
action: 'PUSH' | 'POP' | 'REPLACE'
5
}
Copied!
s3ObjectLink
Enabled only when overrides.s3ObjectLink.emit parameter is set during initialization. Sent when the link button in the object version menu is clicked.
1
interface S3ObjectLinkMessage extends Message {
2
type: 's3ObjectLink'
3
// URL aka route of the object version in the context of the Embed
4
url: string
5
// HTTPS URI of the object version, e.g. https://my-bucket.s3.amazonaws.com/${key}?versionId=${version} (with properly encoded key)
6
s3HttpsUri: string
7
// Bucket the object resides in
8
bucket: string
9
// Object's key
10
key: string
11
// Object's version ID
12
version: string
13
}
Copied!

Testing and debugging

The catalog's /__embed-debug route is a simple driver for testing Embed:
__embed-debug is useful for trying different parameters and inspecting messages passed to and from the Embed.
Its main components are:
  1. 1.
    Inputs for init parameters and button for sending the init command.
  2. 2.
    "Navigate to" button and route input for sending the navigate command.
  3. 3.
    Embed window.
  4. 4.
    Message log.
Last modified 1mo ago