|
| 1 | +<!doctype html> |
| 2 | +<html lang="{{ app()->getLocale() }}"> |
| 3 | + <head> |
| 4 | + <meta charset="utf-8"> |
| 5 | + <meta http-equiv="X-UA-Compatible" content="IE=edge"> |
| 6 | + <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 7 | + <title>Embedding Metabase in Laravel</title> |
| 8 | + |
| 9 | + <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Assistant:400,700" rel="stylesheet""> |
| 10 | +
|
| 11 | + <style type="text/css"> |
| 12 | +
|
| 13 | + * { |
| 14 | + box-sizing: border-box; |
| 15 | + } |
| 16 | +
|
| 17 | + html, |
| 18 | + body, |
| 19 | + .container { |
| 20 | + height: 100%; |
| 21 | + } |
| 22 | +
|
| 23 | + body { |
| 24 | + font-family: 'Assistant', Helvetica, sans-serif; |
| 25 | + margin: 0; |
| 26 | + padding: 1rem; |
| 27 | + } |
| 28 | +
|
| 29 | + @media screen and (min-width: 40em) { |
| 30 | + padding-left: 10rem; |
| 31 | + padding-top: 32rem; |
| 32 | + } |
| 33 | +
|
| 34 | + .container { |
| 35 | + margin-left: auto; |
| 36 | + margin-right: auto; |
| 37 | + } |
| 38 | +
|
| 39 | + @media screen and (min-width: 40em) { |
| 40 | + .container { |
| 41 | + max-width: 80rem; |
| 42 | + } |
| 43 | +
|
| 44 | + article { |
| 45 | + padding-left: 10rem; |
| 46 | + } |
| 47 | + } |
| 48 | +
|
| 49 | + p { |
| 50 | + font-size: 1.12rem; |
| 51 | + max-width: 38.84rem; |
| 52 | + line-height: 1.6rem; |
| 53 | + color: #2E353B; |
| 54 | + } |
| 55 | +
|
| 56 | + @media screen and (min-width: 40em) { |
| 57 | + section { |
| 58 | + padding-top: 4rem; |
| 59 | + padding-bottom: 4rem; |
| 60 | + } |
| 61 | + } |
| 62 | +
|
| 63 | + h1 { |
| 64 | + font-size: 2em; |
| 65 | + } |
| 66 | + @media screen and (min-width: 40em) { |
| 67 | + h1 { |
| 68 | + margin-top: 14rem; |
| 69 | + } |
| 70 | + } |
| 71 | +
|
| 72 | + @media screen and (min-width: 40em) { |
| 73 | + nav { |
| 74 | + margin-top: 6rem; |
| 75 | + margin-bottom: 6rem; |
| 76 | + } |
| 77 | + } |
| 78 | +
|
| 79 | + nav a { |
| 80 | + margin-right: 1rem; |
| 81 | + } |
| 82 | +
|
| 83 | + iframe { |
| 84 | + margin-top: 2rem; |
| 85 | + margin-bottom: 2rem; |
| 86 | + } |
| 87 | +
|
| 88 | + a { |
| 89 | + cursor: pointer; |
| 90 | + color: #509ee3; |
| 91 | + } |
| 92 | +
|
| 93 | + hr { |
| 94 | + border: none; |
| 95 | + height: 1px; |
| 96 | + background-color: #DCE1E4; |
| 97 | + margin: 0; |
| 98 | + max-width: 38.84rem; |
| 99 | + } |
| 100 | +
|
| 101 | + input { |
| 102 | + padding: 1rem; |
| 103 | + border: 1px solid #DCE1E4; |
| 104 | + border-radius: 2px; |
| 105 | + } |
| 106 | +
|
| 107 | + .auth { |
| 108 | + text-align: center; |
| 109 | + max-width: 20rem; |
| 110 | + margin-left: auto; |
| 111 | + margin-right: auto; |
| 112 | + display: flex; |
| 113 | + flex-direction: column; |
| 114 | + justify-content: center; |
| 115 | + height: 100%; |
| 116 | + } |
| 117 | +
|
| 118 | + .auth input { |
| 119 | + width: 100%; |
| 120 | + margin-bottom: 1rem; |
| 121 | + } |
| 122 | +
|
| 123 | + .auth button { |
| 124 | + width: 100%; |
| 125 | + } |
| 126 | +
|
| 127 | + button { |
| 128 | + font-family: 'Assistant', Helvetica, sans-serif; |
| 129 | + border: 1px solid #DCE1E4; |
| 130 | + background-color: #fff; |
| 131 | + padding: 1rem; |
| 132 | + border-radius: 2px; |
| 133 | + font-size: 1rem; |
| 134 | + line-height: 1; |
| 135 | + } |
| 136 | +
|
| 137 | + button:hover { |
| 138 | + cursor: pointer; |
| 139 | + } |
| 140 | +
|
| 141 | + button.primary { |
| 142 | + border-color: #509ee3; |
| 143 | + background-color: #509ee3; |
| 144 | + color: #fff; |
| 145 | + } |
| 146 | +
|
| 147 | + .text-brand { color: #509ee3; } |
| 148 | +
|
| 149 | + pre { |
| 150 | + max-width: 38.84rem; |
| 151 | + border: 1px solid #DCE1E4; |
| 152 | + border-radius: 2px; |
| 153 | + padding: 2rem; |
| 154 | + white-space: pre-wrap; |
| 155 | + } |
| 156 | +
|
| 157 | + </style> |
| 158 | +
|
| 159 | + </head> |
| 160 | + <body> |
| 161 | +
|
| 162 | + <div class="container"> |
| 163 | +
|
| 164 | + <h1>Embedding charts with signed parameters</h1> |
| 165 | + <p> |
| 166 | + This is an example of an embedded chart with a signed parameter. Signed parameters are question parameters that must be signed by the embedding application. |
| 167 | + </p> |
| 168 | + <p> |
| 169 | + The parameter is "User ID". This parameter marked as "Locked". This means that the embedding application's server process must specify a value and sign the request. This prevents an end user of the application from changing the url and seeing other user's charts or dashboards. There is no reference to this ID in the embedded iframe, and it is kept a secret from the end user. |
| 170 | + </p> |
| 171 | +
|
| 172 | + <p> |
| 173 | + To embed this graph in a webpage (as below), you'll need to generate a url on the server by signing a dictionary specifying the resource and it's signed parameters as below |
| 174 | + </p> |
| 175 | +
|
| 176 | +<pre> |
| 177 | +// composer require lcobucci/jwt |
| 178 | +use Lcobucci\JWT\Builder; |
| 179 | +use Lcobucci\JWT\Signer\Hmac\Sha256; |
| 180 | +
|
| 181 | +$metabaseSiteUrl = METABASE_SITE_URL; |
| 182 | +$metabaseSecretKey = METABASE_SECRET_KEY; |
| 183 | +
|
| 184 | +$signer = new Sha256(); |
| 185 | +$token = (new Builder()) |
| 186 | + ->set('resource', [ |
| 187 | + 'question' => 6 |
| 188 | + ]) |
| 189 | + ->set('params', [ |
| 190 | + 'user_id' => $userId |
| 191 | + ]) |
| 192 | + ->sign($signer, $metabaseSecretKey) |
| 193 | + ->getToken(); |
| 194 | +
|
| 195 | +$iframeUrl = "{$metabaseSiteUrl}/embed/question/{$token}#bordered=true&titled=true"; |
| 196 | +</pre> |
| 197 | +<p> |
| 198 | + In the place you wish to embed the chart in your HTML, insert the below: |
| 199 | +</p> |
| 200 | +
|
| 201 | +<pre> |
| 202 | +<iframe |
| 203 | + src="http://<?php echo htmlentities('{{ $iframeUrl }}') ?>" |
| 204 | + frameborder="0" |
| 205 | + width="800" |
| 206 | + height="600" |
| 207 | + allowtransparency |
| 208 | +/></iframe> |
| 209 | +</pre> |
| 210 | +
|
| 211 | + <a href="/">Go back to a global view</a> |
| 212 | + <p> |
| 213 | + This results in the below when put together |
| 214 | + </p> |
| 215 | + <h1>Orders for User: {{ $userId }}</h1> |
| 216 | +
|
| 217 | + <iframe |
| 218 | + src="http://{{ $iframeUrl }}" |
| 219 | + frameborder="0" |
| 220 | + width="800" |
| 221 | + height="600" |
| 222 | + allowtransparency |
| 223 | + /> |
| 224 | +
|
| 225 | + </div> |
| 226 | +
|
| 227 | + </body> |
| 228 | +</html> |
0 commit comments